Introduction
This is an RMarkdown file to introduce the Network Graph set of Metaphors, using R code. We will connect various concepts/ideas and their graph-metaphors.
The method followed will be based on PRIMM:
- PREDICT Inspect the code and guess at what the code might do, write predictions
- RUN the code provided and check what happens
- INFER what the
parameters of the code do and write comments to explain. What bells and whistles can you see?
- MODIFY the
parameters code provided to understand the options available. Write comments to show what you have aimed for and achieved.
- MAKE : take an idea/concept of your own, and graph it.
Predict/Run/Infer -1
Using tidygraph and ggraph
tidygraph and ggraph are modern R packages for network data. Graph Data setup and manipulation is done in tidygraph and graph visualization with ggraph.
tidygraph Data -> “Network Object” in R.
ggraph Network Object -> Plots using a chosen layout/algo.
Both leverage the power of igraph, which is the Big Daddy of all network packages. We will be using the Grey’s Anatomy dataset in our first foray into networks.
Step1. Read the data
grey_nodes <- read_csv("./Data/greys-nodes.csv")
##
## -- Column specification --------------------------------------------------------
## cols(
## name = col_character(),
## sex = col_character(),
## race = col_character(),
## birthyear = col_double(),
## position = col_character(),
## season = col_double(),
## sign = col_character()
## )
grey_edges <- read_csv("./Data/greys-edges.csv")
##
## -- Column specification --------------------------------------------------------
## cols(
## from = col_character(),
## to = col_character(),
## weight = col_double(),
## type = col_character()
## )
grey_nodes
## # A tibble: 54 x 7
## name sex race birthyear position season sign
## <chr> <chr> <chr> <dbl> <chr> <dbl> <chr>
## 1 Addison Montgomery F White 1967 Attending 1 Libra
## 2 Adele Webber F Black 1949 Non-Staff 2 Leo
## 3 Teddy Altman F White 1969 Attending 6 Pisces
## 4 Amelia Shepherd F White 1981 Attending 7 Libra
## 5 Arizona Robbins F White 1976 Attending 5 Leo
## 6 Rebecca Pope F White 1975 Non-Staff 3 Gemini
## 7 Jackson Avery M Black 1981 Resident 6 Leo
## 8 Miranda Bailey F Black 1969 Attending 1 Virgo
## 9 Ben Warren M Black 1972 Other 6 Aquarius
## 10 Henry Burton M White 1972 Non-Staff 7 Cancer
## # ... with 44 more rows
grey_edges
## # A tibble: 57 x 4
## from to weight type
## <chr> <chr> <dbl> <chr>
## 1 Leah Murphy Arizona Robbins 2 friends
## 2 Leah Murphy Alex Karev 4 benefits
## 3 Lauren Boswell Arizona Robbins 1 friends
## 4 Arizona Robbins Callie Torres 1 friends
## 5 Callie Torres Erica Hahn 6 friends
## 6 Callie Torres Alex Karev 12 benefits
## 7 Callie Torres Mark Sloan 5 professional
## 8 Callie Torres George O'Malley 2 professional
## 9 George O'Malley Izzie Stevens 3 professional
## 10 George O'Malley Meredith Grey 4 friends
## # ... with 47 more rows
Questions and Inferences: Check the console output thumbnail below. What does for example name = col_character mean? What attributes (i.e. extra information) are seen for Nodes and Edges? Understand the data in both nodes and edges as shown in the second and third thumbnails. Write some comments and inferences here.
Step 2.Create a network object using tidygraph:
Key function:
tbl_graph(): (aka “tibble graph”). Key arguments: nodes, edges and directed. Note this is a very versatile command and can take many input forms, such as data structures that result from other packages. Type ?tbl_graph in the Console and see the Usage section.
ga <- tbl_graph(nodes = grey_nodes, edges = grey_edges,directed = FALSE)
ga
## # A tbl_graph: 54 nodes and 57 edges
## #
## # An undirected simple graph with 4 components
## #
## # Node Data: 54 x 7 (active)
## name sex race birthyear position season sign
## <chr> <chr> <chr> <dbl> <chr> <dbl> <chr>
## 1 Addison Montgomery F White 1967 Attending 1 Libra
## 2 Adele Webber F Black 1949 Non-Staff 2 Leo
## 3 Teddy Altman F White 1969 Attending 6 Pisces
## 4 Amelia Shepherd F White 1981 Attending 7 Libra
## 5 Arizona Robbins F White 1976 Attending 5 Leo
## 6 Rebecca Pope F White 1975 Non-Staff 3 Gemini
## # ... with 48 more rows
## #
## # Edge Data: 57 x 4
## from to weight type
## <int> <int> <dbl> <chr>
## 1 5 47 2 friends
## 2 21 47 4 benefits
## 3 5 46 1 friends
## # ... with 54 more rows
Questions and Inferences: What information does the graph object contain? What attributes do the nodes have? What about the edges?
Step 3. Plot using ggraph
3a. Quick Plot: autograph() This is to check quickly is the data is imported properly and to decide upon going on to a more elaborate plotting.
autograph(ga)

Questions and Inferences: Describe this graph, in simple words here. Try to use some of the new domain words we have just acquired: nodes/edges, connected/disconnected, directed/undirected.
3b. More elaborate plot
Key functions:
ggraph(layout = "......"): Create classic node-edge diagrams; i.e. Sets up the graph. Rather like ggplot for networks!
Two kinds of geom: one set for nodes, and another for edges
geom_node_point(aes(.....)): Draws node as “points”. Alternatives are circle / arc_bar / tile / voronoi. Remember the geoms that we have seen before in Grammar of Graphics!
geom_edge_link(aes(.....)): Draws edges as “links”. Alternatives are arc / bend / elbow / hive / loop / parallel / diagonal / point / span /tile.
geom_node_text(aes(label = ......), repel = TRUE): Adds text labels (non-overlapping). Alternatives are label /...
labs(title = "....", subtitle = "....", caption = "...."): Change main titles, axis labels and legend titles. We know this from our work with ggplot.
# Write Comments next to each line
# About what that line does for the overall graph
ggraph(graph = ga, layout = "kk") +
#
geom_edge_link(width = 2, color = "pink") +
#
geom_node_point(
shape = 21,
size = 8,
fill = "blue",
color = "green",
stroke = 2
) +
#
labs(title = "Whoo Hoo! My first silly Grey's Anatomy graph in R!",
subtitle = "Why did the Dean put me in this course...",
caption = "Bro, they are doing **cool** things in the other
classes...")

Questions and Inferences: What parameters have been changed here, compared to the earlier graph? Where do you see these changes in the code above?
Let us Play with this graph and see if we can make some small changes. Colour? Fill? Width? Size? Stroke? Labs? Of course!
# Change the parameters in each of the commands here to new ones
# Use fixed values for colours or sizes...etc.
ggraph(graph = ga, layout = "kk") +
geom_edge_link(width = 2) +
geom_node_point(shape = 21, size = 8,
fill = "blue",
color = "green",
stroke = 2) +
labs(title = "Whoo Hoo! My next silly Grey's Anatomy graph in R!",
subtitle = "Why did Ramesh put me in this course...",
caption = "Bro, they are doing cool things in the other
classes...")

Questions and Inferences: What did the shape parameter achieve? What are the possibilities with shape? How about including alpha?
3c. Aesthetic Mapping from Node and Edge attribute columns
Up to now, we have assigned specific numbers to geometric aesthetics such as shape and size. Now we are ready ( maybe ?) change the meaning and significance of the entire graph and each element within it, and use aesthetics / metaphoric mappings to achieve new meanings or insights. Let us try using aes() inside each geom to map a variable to a geometric aspect.
Don’t try to use more than 2 aesthetic mappings simultaneously!!
The node elements we can tweak are:
- Types of Nodes:
geom_node_****()
- Node Parameters: inside
geom_node_****(aes(...............))
-aes(alpha = node-variable) : opacity; a value between 0 and 1
-aes(shape = node-variable) : node shape
-aes(colour = node-variable) : node colour
-aes(fill = node-variable) : fill colour for node
-aes(size = node-variable) : size of node
The edge elements we can tweak are:
- Type of Edges"
geom_edge_****()
- Edge Parameters: inside
geom_edge_****(aes(...............))
-aes(colour = edge-variable) : colour of the edge
-aes(width = edge-variable) : width of the edge
-aes(label = some_variable) : labels for the edge
Type ?geom_node_point and ?geom-edge_link in your Console for more information.
ggraph(graph = ga, layout = "fr") +
geom_edge_link0() + # add mapping here
geom_node_point() + # add mapping here
geom_node_label(aes(label = name), # modify this mapping
repel = TRUE, max.overlaps = 20,
alpha = 0.6,
size = 3) +
labs(title = "Whoo Hoo! Yet another Grey's Anatomy graph in R!")

Questions and Inferences: Describe some of the changes here. What types of edges worked? Which variables were you able to use for nodes and edges and how? What did not work with either of the two?
Predict/Reuse/Infer-2
# Arc diagram
ggraph(ga, layout = "linear") +
geom_edge_arc(aes(width = weight), alpha = 0.8) +
scale_edge_width(range = c(0.2, 2)) +
geom_node_point(size = 2, colour = "red") +
labs(edge_width = "Weight") +
theme_graph()+
theme(legend.position = "top")

Questions and Inferences: How does this graph look “metaphorically” different? Do you see a difference in the relationships between people here? Why?
# Coord diagram, circular
ggraph(ga, layout = "linear", circular = TRUE) +
geom_edge_arc(aes(width = weight), alpha = 0.8) +
scale_edge_width(range = c(0.2, 2)) +
geom_node_point(size = 4,colour = "red") +
geom_node_text(aes(label = name),repel = TRUE, size = 3,
max.overlaps = 20) +
labs(edge_width = "Weight") +
theme_graph()+
theme(legend.position = "right",
aspect.ratio = 1)

Questions and Inferences: How does this graph look “metaphorically” different? Do you see a difference in the relationships between people here? Why?
Hierarchical layouts
These provide for some alternative metaphorical views of networks. Note that not all layouts are possible for all datasets!!
# setting theme_graph
set_graph_style()
# This dataset contains the graph that describes the class
# hierarchy for the Flare visualization library.
# Type ?flare in your Console
head(flare$vertices)
## name size shortName
## 1 flare.analytics.cluster.AgglomerativeCluster 3938 AgglomerativeCluster
## 2 flare.analytics.cluster.CommunityStructure 3812 CommunityStructure
## 3 flare.analytics.cluster.HierarchicalCluster 6714 HierarchicalCluster
## 4 flare.analytics.cluster.MergeEdge 743 MergeEdge
## 5 flare.analytics.graph.BetweennessCentrality 3534 BetweennessCentrality
## 6 flare.analytics.graph.LinkDistance 5731 LinkDistance
head(flare$edges)
## from to
## 1 flare.analytics.cluster flare.analytics.cluster.AgglomerativeCluster
## 2 flare.analytics.cluster flare.analytics.cluster.CommunityStructure
## 3 flare.analytics.cluster flare.analytics.cluster.HierarchicalCluster
## 4 flare.analytics.cluster flare.analytics.cluster.MergeEdge
## 5 flare.analytics.graph flare.analytics.graph.BetweennessCentrality
## 6 flare.analytics.graph flare.analytics.graph.LinkDistance
# flare class hierarchy
graph = tbl_graph(edges = flare$edges, nodes = flare$vertices)
# dendrogram
ggraph(graph, layout = "dendrogram") +
geom_edge_diagonal() +
labs(title = "Dendrogram")

# circular dendrogram
ggraph(graph, layout = "dendrogram", circular = TRUE) +
geom_edge_diagonal() +
geom_node_point(aes(filter = leaf)) +
coord_fixed()+
labs(title = "Circular Dendrogram")

# rectangular tree map
ggraph(graph, layout = "treemap", weight = size) +
geom_node_tile(aes(fill = depth), size = 0.25) +
labs(title = "Rectangular Tree Map")

# circular tree map
ggraph(graph, layout = "circlepack", weight = size) +
geom_node_circle(aes(fill = depth), size = 0.25, n = 50) +
coord_fixed() +
labs(title = "Circular Tree Map")

# icicle
ggraph(graph, layout = "partition") +
geom_node_tile(aes(y = -y, fill = depth))

# sunburst (circular icicle)
ggraph(graph, layout = "partition", circular = TRUE) +
geom_node_arc_bar(aes(fill = depth)) +
coord_fixed() +
labs(title = "Circular Icicle")

Questions and Inferences: How do graphs look “metaphorically” different? Do they reveal different aspects of the group? How?
Faceting
Faceting allows to create sub-plots according to the values of a qualitative attribute on nodes or edges.
# setting theme_graph
set_graph_style()
# facet edges by type
ggraph(ga,layout = "linear", circular = TRUE) +
geom_edge_link(aes(color = type)) +
geom_node_point() +
facet_edges(~ type)

# facet nodes by sex
ggraph(ga,layout = "linear", circular = TRUE) +
geom_edge_link() +
geom_node_point() +
facet_nodes(~race)

# facet both nodes and edges
ggraph(ga,layout = "linear", circular = TRUE) +
geom_edge_link(aes(color = type)) +
geom_node_point() +
facet_graph(type ~ race) +
th_foreground(border = TRUE)

Questions and Inferences: Does splitting up the main graph into subnetworks give you more insight? Describe some of these.
Network analysis with tidygraph
The data frame graph representation can be easily augmented with metrics or statistics computed on the graph. Remember how we computed counts with the penguin dataset in Grammar of Graphics. Before computing a metric on nodes or edges use the activate() function to activate either node or edge data frames. Use dplyr verbs (filter, arrange, mutate) to achieve your computation in the proper way.
Network Centrality
Centrality is a an “ill-defined” metric of node and edge importance in a network. It is therefore calculated in many ways. Type ?centrality in your Console.
[Standards](https://imgs.xkcd.com/comics/standards.png,align = "center)
Let’s add a few columns to the nodes and edges based on network centrality measures:
ga %>%
activate(nodes) %>%
# Most connections?
mutate(degree = centrality_degree()) %>%
filter(degree > 0) %>%
activate(edges) %>%
# "Busiest" edge?
mutate(betweenness = centrality_edge_betweenness()
)
## # A tbl_graph: 54 nodes and 57 edges
## #
## # An undirected simple graph with 4 components
## #
## # Edge Data: 57 x 5 (active)
## from to weight type betweenness
## <int> <int> <dbl> <chr> <dbl>
## 1 5 47 2 friends 20.3
## 2 21 47 4 benefits 44.7
## 3 5 46 1 friends 39
## 4 5 41 1 friends 66.3
## 5 18 41 6 friends 39
## 6 21 41 12 benefits 91.5
## # ... with 51 more rows
## #
## # Node Data: 54 x 8
## name sex race birthyear position season sign degree
## <chr> <chr> <chr> <dbl> <chr> <dbl> <chr> <dbl>
## 1 Addison Montgomery F White 1967 Attending 1 Libra 3
## 2 Adele Webber F Black 1949 Non-Staff 2 Leo 1
## 3 Teddy Altman F White 1969 Attending 6 Pisces 4
## # ... with 51 more rows
Packages tidygraph and ggraph can be pipelined to perform analysis and visualization tasks in one go.
# setting theme_graph
set_graph_style()
ga %>%
activate(nodes) %>%
# Who has the most connections?
mutate(degree = centrality_degree()) %>%
activate(edges) %>%
# Who is the go-through person?
mutate(betweenness = centrality_edge_betweenness()) %>%
# Now to continue with plotting
ggraph(layout = "nicely") +
geom_edge_link(aes(alpha = betweenness)) +
geom_node_point(aes(size = degree, colour = degree)) +
# discrete colour legend
scale_color_gradient(guide = "legend")

# or even less typing
ggraph(ga,layout = "nicely") +
geom_edge_link(aes(alpha = centrality_edge_betweenness())) +
geom_node_point(aes(fill = centrality_degree(),
colour = centrality_degree())) +
scale_color_gradient(guide = "legend",
low = "green",
high = "red")

Analyse and visualize network: communities
# setting theme_graph
set_graph_style()
# visualize communities of nodes
ga %>%
#make_undirected_graph() %>%
#activate(edges) %>% mutate(from = as.numeric(from),
# to = as.numeric(to)) %>%
activate(nodes) %>%
mutate(community = as.factor(group_louvain())) %>%
ggraph(layout = "graphopt") +
geom_edge_link() +
geom_node_point(aes(color = community), size = 5)

Good, you are now a gRaphista !!
Bonus Material for the Intrepid
Exploring the VisNetwork package. Make graphs wiggle and shake using tidy commands!
The visNetwork() function uses a nodes list and edges list to create an interactive graph. The nodes list must include an “id” column, and the edge list must have “from” and “to” columns. The function also plots the labels for the nodes, using the names of the cities from the “label” column in the node list.
library(visNetwork)
# Prepare the data for plotting by visNetwork
grey_nodes
## # A tibble: 54 x 7
## name sex race birthyear position season sign
## <chr> <chr> <chr> <dbl> <chr> <dbl> <chr>
## 1 Addison Montgomery F White 1967 Attending 1 Libra
## 2 Adele Webber F Black 1949 Non-Staff 2 Leo
## 3 Teddy Altman F White 1969 Attending 6 Pisces
## 4 Amelia Shepherd F White 1981 Attending 7 Libra
## 5 Arizona Robbins F White 1976 Attending 5 Leo
## 6 Rebecca Pope F White 1975 Non-Staff 3 Gemini
## 7 Jackson Avery M Black 1981 Resident 6 Leo
## 8 Miranda Bailey F Black 1969 Attending 1 Virgo
## 9 Ben Warren M Black 1972 Other 6 Aquarius
## 10 Henry Burton M White 1972 Non-Staff 7 Cancer
## # ... with 44 more rows
grey_edges
## # A tibble: 57 x 4
## from to weight type
## <chr> <chr> <dbl> <chr>
## 1 Leah Murphy Arizona Robbins 2 friends
## 2 Leah Murphy Alex Karev 4 benefits
## 3 Lauren Boswell Arizona Robbins 1 friends
## 4 Arizona Robbins Callie Torres 1 friends
## 5 Callie Torres Erica Hahn 6 friends
## 6 Callie Torres Alex Karev 12 benefits
## 7 Callie Torres Mark Sloan 5 professional
## 8 Callie Torres George O'Malley 2 professional
## 9 George O'Malley Izzie Stevens 3 professional
## 10 George O'Malley Meredith Grey 4 friends
## # ... with 47 more rows
# Relabel greys anatomy nodes and edges for VisNetwork
grey_nodes_vis <- grey_nodes %>%
rowid_to_column(var = "id") %>%
rename("label" = name) %>%
mutate(sex = case_when(sex == "F" ~ "Female",
sex == "M" ~ "Male")) %>%
replace_na(., list(sex = "Transgender?")) %>%
rename("group" = sex)
grey_nodes_vis
## # A tibble: 54 x 8
## id label group race birthyear position season sign
## <int> <chr> <chr> <chr> <dbl> <chr> <dbl> <chr>
## 1 1 Addison Montgomery Female White 1967 Attending 1 Libra
## 2 2 Adele Webber Female Black 1949 Non-Staff 2 Leo
## 3 3 Teddy Altman Female White 1969 Attending 6 Pisces
## 4 4 Amelia Shepherd Female White 1981 Attending 7 Libra
## 5 5 Arizona Robbins Female White 1976 Attending 5 Leo
## 6 6 Rebecca Pope Female White 1975 Non-Staff 3 Gemini
## 7 7 Jackson Avery Male Black 1981 Resident 6 Leo
## 8 8 Miranda Bailey Female Black 1969 Attending 1 Virgo
## 9 9 Ben Warren Male Black 1972 Other 6 Aquarius
## 10 10 Henry Burton Male White 1972 Non-Staff 7 Cancer
## # ... with 44 more rows
grey_edges_vis <- grey_edges %>%
select(from, to) %>%
left_join(., grey_nodes_vis, by = c("from" = "label")) %>%
left_join(., grey_nodes_vis, by = c("to" = "label")) %>%
select("from"= id.x, "to" = id.y)
grey_edges_vis
## # A tibble: 57 x 2
## from to
## <int> <int>
## 1 47 5
## 2 47 21
## 3 46 5
## 4 5 41
## 5 41 18
## 6 41 21
## 7 41 37
## 8 41 31
## 9 31 20
## 10 31 17
## # ... with 47 more rows
Using fontawesome icons
grey_nodes_vis %>%
visNetwork(nodes = ., edges = grey_edges_vis) %>%
visNodes(font = list(size = 40)) %>%
# Colour and icons for each of the gender-groups
visGroups(groupname = "Female", shape = "icon",
icon = list(code = "f182", size = 75, color = "tomato"),
shadow = list(enabled = TRUE)) %>%
visGroups(groupname = "Male", shape = "icon",
icon = list(code = "f183", size = 75, color = "slateblue"),
shadow = list(enabled = TRUE)) %>%
visGroups(groupname = "Transgender?", shape = "icon",
icon = list(code = "f22c", size = 75, color = "fuchsia"),
shadow = list(enabled = TRUE)) %>%
#visLegend() %>%
#Add the fontawesome icons!!
addFontAwesome() %>%
# Add Interaction Controls
visInteraction(navigationButtons = TRUE,
hover = TRUE,
selectConnectedEdges = TRUE,
hoverConnectedEdges = TRUE,
zoomView = TRUE)
There is another family of icons available in visNetwork, called ionicons. Let’s see how they look:
grey_nodes_vis %>%
visNetwork(nodes = ., edges = grey_edges_vis,) %>%
visLayout(randomSeed = 12345) %>%
visNodes(font = list(size = 50)) %>%
visEdges(color = "green") %>%
visGroups(
groupname = "Female",
shape = "icon",
icon = list(
face = 'Ionicons',
code = "f25d",
color = "fuchsia",
size = 125
)
) %>%
visGroups(
groupname = "Male",
shape = "icon",
icon = list(
face = 'Ionicons',
code = "f202",
color = "green",
size = 125
)
) %>%
visGroups(
groupname = "Transgender?",
shape = "icon",
icon = list(
face = 'Ionicons',
code = "f233",
color = "dodgerblue",
size = 125
)
) %>%
visLegend() %>%
addIonicons() %>%
visInteraction(
navigationButtons = TRUE,
hover = TRUE,
selectConnectedEdges = TRUE,
hoverConnectedEdges = TRUE,
zoomView = TRUE
)
Some idea of interactivity and controls with visNetwork:
library(visNetwork)
# let's look again at the data
starwars_nodes <- read_csv("./Data/star-wars-network-nodes.csv")
##
## -- Column specification --------------------------------------------------------
## cols(
## name = col_character(),
## id = col_double()
## )
starwars_edges <- read_csv("./Data/star-wars-network-edges.csv")
##
## -- Column specification --------------------------------------------------------
## cols(
## source = col_character(),
## target = col_character(),
## weight = col_double()
## )
# We need to rename starwars nodes dataframe and edge dataframe columns for visNetwork
starwars_nodes_vis <-
starwars_nodes %>%
rename("label" = name)
# Convert from and to columns to **node ids**
starwars_edges_vis <-
starwars_edges %>%
# Matching Source <- Source Node id ("id.x")
left_join(., starwars_nodes_vis, by = c("source" = "label")) %>%
# Matching Target <- Target Node id ("id.y")
left_join(., starwars_nodes_vis, by = c("target" = "label")) %>%
# Select "id.x" and "id.y" ONLY
# Rename them as "from" and "to"
# keep "weight" column for aesthetics of edges
select("from" = id.x, "to" = id.y, "value" = weight)
# Check everything once
starwars_nodes_vis
## # A tibble: 22 x 2
## label id
## <chr> <dbl>
## 1 R2-D2 0
## 2 CHEWBACCA 1
## 3 C-3PO 2
## 4 LUKE 3
## 5 DARTH VADER 4
## 6 CAMIE 5
## 7 BIGGS 6
## 8 LEIA 7
## 9 BERU 8
## 10 OWEN 9
## # ... with 12 more rows
starwars_edges_vis
## # A tibble: 60 x 3
## from to value
## <dbl> <dbl> <dbl>
## 1 2 0 17
## 2 3 0 13
## 3 10 0 6
## 4 7 0 5
## 5 13 0 5
## 6 1 0 3
## 7 16 0 1
## 8 1 10 7
## 9 2 1 5
## 10 1 3 16
## # ... with 50 more rows
Ok, let’s make things move and shake!!
visNetwork(nodes = starwars_nodes_vis,
edges = starwars_edges_vis) %>%
visNodes(font = list(size = 30), shape = "icon",
icon = list(code = "f1e3", size = 75)) %>%
addFontAwesome() %>%
visEdges(color = "red")
visNetwork(nodes = starwars_nodes_vis,
edges = starwars_edges_vis) %>%
visNodes(font = list(size = 30)) %>%
visEdges(color = "red")
Your Assignments:
Make-1 : With a ready made dataset
Step 1. Fire up a new RMarkdown. Write your name, file_name and date.
Step 2. Take any one of the “Make1-Datasets” datasets decribed below.
Step 3. RMarkdown contents:
- Introduce / Inspect in R your data and describe - Introduce your Purpose - Create graph objects. - Write comments in the code - Write narrative in text with sections, bold ,italic etc.
Step 4. Knit before you submit. Submit only your knittable .Rmd file.
Make1 - Datasets:
- Airline Data:
- Start with this bit of code in your second chunk, after
set up
airline_nodes <- read_csv(“./Data/AIRLINES-NODES.csv”) ) %>% mutate(Id = Id + 1) airline_edges <- read_csv(“./Data/AIRLINES-EDGES.csv”) %>% mutate(Source = Source + 1, Target = Target + 1)
- The Famous Zachary Karate Club dataset
- Start with pulling this data into your Rmarkdown:
data(“karate”,package= “igraphdata”) karate
- Try
?karate in the console
- Note that this is not a set of nodes, nor edges, but already a graph-object!
- So no need to create a graph object using
tbl_graph.
- You will need to just go ahead and plot using
ggraph.
- Game of Thrones:
- Start with pulling this data into your Rmarkdown:
GoT <- read_rds(“/Data/GoT/GoT.RDS”)
- Note that this is a list of 7 graphs from Game of Thrones.
- Select one using
GoT[[index]] where index = 1…7 and then plot directly.
- Try to access the nodes and edges and modify them using any attribute data
- Any other graph dataset from
igraphdata (type ?igraphdata in console)
- Ask me for help if you need any
Make-2: Literary Network with TV Show / Book / Story / Play
This is in groups. Groups of 4.
You need to create a Network Graph for your favourite Book, play, TV serial or Show. (E.g. Friends, BBT, or LB or HIMYM…or Hamlet, Little Women , Pride and Prejudice, or LoTR)
Step 1. Go to: Literary Networks for instructions. (Instructions are on also Teams -> Files.)
Step 2. Make your data using the instructions.
In the nodes excel, use id and names as your columns. Any other details in other columns to the right.
In your edges excel, use from and to are your first columns. Entries in these columns can be names or ids but be consistent and don’t mix.
Step 3. Decide on 3 answers that you to seek and plan to make graphs for.
Step 4. Create graph objects. Say 3 visualizations.
Step 5. Write comments/answers in the code and narrative text. Add pictures from the web using Markdown syntax.
Step 6. Write Reflection ( ok, a short one!) inside your RMarkdown. Make sure it knits!!
Step 7. Group Submission: Submit the knittable .Rmd file AND the data. RMarkdown with joint authorship. Each person submits on their Assignments. All get the same grade on this one.
Ask me for clarifications on what to do after you have read the Instructions in your group.
LS0tDQp0aXRsZTogTGFiIDA3IC0gVGhlIEdyYW1tYXIgb2YgTmV0d29ya3MNCmF1dGhvcjogQXJ2aW5kIFZlbmthdGFkcmkNCmRhdGU6ICcyMDIxLTA2LTIyJw0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICB0b2NfZGVwdGg6IDINCiAgICBudW1iZXJfc2VjdGlvbnM6IFRSVUUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpsaWJyYXJ5KGV4dHJhZm9udCkNCiMgUnVuIHRoaXMgb25lIHRpbWUNCiNleHRyYWZvbnQ6OmZvbnRfaW1wb3J0KCkNCmxvYWRmb250cygpDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIEZvciBHZW5lcmFsIERhdGEgTWFuaXB1bGF0aW9uDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBOZXR3b3JrIEFuYWx5c2lzIExpYnJhcnkgKEhhbmRsZSBkYXRhIGFuZCBWaXopDQpsaWJyYXJ5KGlncmFwaCkNCmxpYnJhcnkobmV0cmFua3IpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgRm9yIE5ldHdvcmsgIk1hbmlwdWxhdGlvbiINCmxpYnJhcnkodGlkeWdyYXBoKQ0KDQojIEZvciBOZXR3b3JrIFZpc3VhbGl6YXRpb24NCmxpYnJhcnkoZ2dyYXBoKQ0KbGlicmFyeShncmFwaGxheW91dHMpDQoNCiMgRm9yICJOZXR3b3JrIiBEYXRhc2V0cw0KbGlicmFyeShpZ3JhcGhkYXRhKQ0KYGBgDQoNCiMgSW50cm9kdWN0aW9uDQoNClRoaXMgaXMgYW4gUk1hcmtkb3duIGZpbGUgdG8gaW50cm9kdWNlIHRoZSBgTmV0d29yayBHcmFwaGAgc2V0IG9mDQpNZXRhcGhvcnMsIHVzaW5nIGBSYCBjb2RlLiBXZSB3aWxsIGNvbm5lY3QgdmFyaW91cyBgY29uY2VwdHMvaWRlYXNgIGFuZA0KdGhlaXIgYGdyYXBoLW1ldGFwaG9yc2AuDQoNClRoZSBtZXRob2QgZm9sbG93ZWQgd2lsbCBiZSBiYXNlZCBvbg0KW1BSSU1NXShodHRwczovL2Jsb2dzLmtjbC5hYy51ay9jc2VyLzIwMTcvMDkvMDEvcHJpbW0tYS1zdHJ1Y3R1cmVkLWFwcHJvYWNoLXRvLXRlYWNoaW5nLXByb2dyYW1taW5nLyk6DQoNCi0gICAqKlBSRURJQ1QqKiBJbnNwZWN0IHRoZSBjb2RlIGFuZCBndWVzcyBhdCB3aGF0IHRoZSBjb2RlIG1pZ2h0IGRvLA0KICAgICoqd3JpdGUgcHJlZGljdGlvbnMqKg0KLSAgICoqUlVOKiogdGhlIGNvZGUgcHJvdmlkZWQgYW5kIGNoZWNrIHdoYXQgaGFwcGVucw0KLSAgICoqSU5GRVIqKiB3aGF0IHRoZSBgcGFyYW1ldGVyc2Agb2YgdGhlIGNvZGUgZG8gYW5kICoqd3JpdGUgY29tbWVudHMgdG8gZXhwbGFpbioqLiBXaGF0IGJlbGxzIGFuZCB3aGlzdGxlcyBjYW4geW91IHNlZT8NCi0gICAqKk1PRElGWSoqIHRoZSBgcGFyYW1ldGVyc2AgY29kZSBwcm92aWRlZCB0byB1bmRlcnN0YW5kIHRoZQ0KICAgIGBvcHRpb25zYCBhdmFpbGFibGUuICoqV3JpdGUgY29tbWVudHMqKiB0byBzaG93IHdoYXQgeW91IGhhdmUgYWltZWQgZm9yIGFuZCBhY2hpZXZlZC4NCi0gICAqKk1BS0UqKiA6IHRha2UgYW4gaWRlYS9jb25jZXB0IG9mIHlvdXIgb3duLCBhbmQgZ3JhcGggaXQuDQoNCiMjIEdyYXBoIE1ldGFwaG9ycw0KDQpOZXR3b3JrIGdyYXBocyBhcmUgY2hhcmFjdGVyaXplZCBieSB0d28ga2V5IHRlcm1zOiAqKm5vZGVzKiogYW5kDQoqKmVkZ2VzKioNCg0KMS4gIGBOb2Rlc2AgOiAqKkVudGl0aWVzKioNCg0KICAgIC0gICBNZXRhcGhvcnM6IEluZGl2aWR1YWwgUGVvcGxlPyBUaGluZ3M/IElkZWFzPyBQbGFjZXM/IHRvIGJlDQogICAgICAgIGNvbm5lY3RlZCBpbiB0aGUgbmV0d29yay4NCiAgICAtICAgU3lub255bXM6IGB2ZXJ0aWNlc2AuIE5vZGVzIGhhdmUgYElEc2AuDQoNCjIuICBgRWRnZXNgOiAqKkNvbm5lY3Rpb25zKioNCg0KICAgIC0gICBNZXRhcGhvcnM6IEludGVyYWN0aW9ucz8gUmVsYXRpb25zaGlwcz8gSW5mbHVlbmNlPyBMZXR0ZXJzIHNlbnQNCiAgICAgICAgYW5kIHJlY2VpdmVkPyBEZXBlbmRlbmNlPyBiZXR3ZWVuIHRoZSBlbnRpdGllcy4NCiAgICAtICAgU3lub255bXM6IGBsaW5rc2AsIGB0aWVzYC4NCg0KSW4gUiwgd2UgY3JlYXRlIG5ldHdvcmsgcmVwcmVzZW50YXRpb25zIHVzaW5nIG5vZGUgYW5kIGVkZ2UgaW5mb3JtYXRpb24uDQoqT25lIHdheSogaW4gd2hpY2ggdGhlc2UgY291bGQgYmUgb3JnYW5pemVkIGFyZTogLSBgTm9kZSBsaXN0YDogYSBkYXRhDQpmcmFtZSB3aXRoIGEgc2luZ2xlIGNvbHVtbiBsaXN0aW5nIHRoZSBub2RlIElEcyBmb3VuZCBpbiB0aGUgZWRnZSBsaXN0Lg0KWW91IGNhbiBhbHNvIGFkZCAqKmF0dHJpYnV0ZSBjb2x1bW5zKiogdG8gdGhlIGRhdGEgZnJhbWUgc3VjaCBhcyB0aGUNCm5hbWVzIG9mIHRoZSBub2RlcyBvciBncm91cGluZyB2YXJpYWJsZXMuICggVHlwZT8gQ2xhc3M/IEZhbWlseT8NCkNvdW50cnk/IFN1YmplY3Q/IFJhY2U/ICkNCg0KKy0tLS0rLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IElEIHwgTm9kZSBOYW1lICAgICAgfCBBdHRyaWJ1dGU/IFF1YWxpdGllcz9DYXRlZ29yaWVzPyBGYW1pbHk/ICAgICAgIHwNCnwgICAgfCAgICAgICAgICAgICAgICB8IENvdW50cnk/UGxhbmV0PyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KKy0tLS0rLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IDEgIHwgTmVkICAgICAgICAgICAgfCBOdXJzZXJ5IFNjaG9vbCBUZWFjaGVyICAgICAgICAgICAgICAgICAgICAgICAgIHwNCistLS0tKy0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCAyICB8IEphZ3VhciBQYXcgICAgIHwgTWFpbiBDaGFyYWN0ZXIsIEFwb2NhbHlwdG8gICAgICAgICAgICAgICAgICAgICB8DQorLS0tLSstLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCnwgMyAgfCBKb2huIFNub3cgICAgICB8IEVwaWRlbWlvbG9naXN0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KKy0tLS0rLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQoNCjogTm9kZSBUYWJsZQ0KDQotICAgYEVkZ2UgbGlzdGA6IGRhdGEgZnJhbWUgY29udGFpbmluZyB0d28gY29sdW1uczogKipzb3VyY2Ugbm9kZSoqIGFuZA0KICAgICoqZGVzdGluYXRpb24gbm9kZSoqIG9mIGFuIGBlZGdlYC4gU291cmNlIGFuZCBEZXN0aW5hdGlvbiBoYXZlDQogICAgYG5vZGUgSURzYC4NCi0gICBgV2VpZ2h0ZWQgbmV0d29yayBncmFwaGA6IEFuIGVkZ2UgbGlzdCBjYW4gYWxzbyBjb250YWluIGFkZGl0aW9uYWwNCiAgICBjb2x1bW5zIGRlc2NyaWJpbmcgYXR0cmlidXRlcyBvZiB0aGUgZWRnZXMgc3VjaCBhcyBhIG1hZ25pdHVkZQ0KICAgIGFzcGVjdCBmb3IgYW4gZWRnZS4gSWYgdGhlIGVkZ2VzIGhhdmUgYSBtYWduaXR1ZGUgYXR0cmlidXRlIHRoZQ0KICAgIGdyYXBoIGlzIGNvbnNpZGVyZWQgd2VpZ2h0ZWQuDQoNCistLS0tLS0tKy0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IEZyb20gIHwgVG8gICAgfCBSZWxhdGlvbnNoaXAgICAgICAgICAgICAgfCBXZWlnaHRhZ2UgICAgICAgICAgICAgICAgfA0KKz09PT09PT0rPT09PT09PSs9PT09PT09PT09PT09PT09PT09PT09PT09PSs9PT09PT09PT09PT09PT09PT09PT09PT09PSsNCnwgMSAgICAgfCAzICAgICB8IEZpbmFuY2lhbCBEZWFsaW5ncyAgICAgICB8IDYgICAgICAgICAgICAgICAgICAgICAgICB8DQorLS0tLS0tLSstLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCAyICAgICB8IDEgICAgIHwgSGlzdG9yeSBMZXNzb25zICAgICAgICAgIHwgMiAgICAgICAgICAgICAgICAgICAgICAgIHwNCistLS0tLS0tKy0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IDIgICAgIHwgMyAgICAgfCBWYWNjaW5hdGlvbiAgICAgICAgICAgICAgfCAxNSAgICAgICAgICAgICAgICAgICAgICAgfA0KKy0tLS0tLS0rLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCg0KOiBFZGdlcyBUYWJsZQ0KDQotICAgYExheW91dGA6IEEgKipnZW9tZXRyaWMqKiBhcnJhbmdlbWVudCBvZiBgbm9kZXNgIGFuZCBgZWRnZXNgLg0KLSAgIE1ldGFwaG9yczogTG9jYXRpb24/IFNwYWNpbmc/IERpc3RhbmNlPyBDb29yZGluYXRlcz8gQ29sb3VyPyBTaGFwZT8gU2l6ZT8gUHJvdmlkZXMgdmlzdWFsIGluc2lnaHQgZHVlIHRvIHRoZSBgYXJyYW5nZW1lbnRgLiAgDQotICAgYExheW91dCBBbGdvcml0aG1zYCA6IGBNZXRob2RgIHRvIGFycmFuZ2VzIGBub2Rlc2AgYW5kIGBlZGdlc2Agd2l0aA0KICAgIHRoZSBhaW0gb2Ygb3B0aW1pemluZyBzb21lIGBtZXRyaWNgIC4NCi0gICBNZXRhcGhvcnM6IE5vZGVzIGFyZSBgbWFzc2VzYCBhbmQgZWRnZXMgYXJlIGBzcHJpbmdzYC4gVGhlIExheW91dA0KICAgIGFsZ29yaXRobSBtaW5pbWl6ZXMgdGhlIHN0cmV0Y2hpbmcgYW5kIGNvbXByZXNzaW5nIG9mIGFsbA0KICAgIHNwcmluZ3MuKEJUVywgYXJlIHRoZSBTcHJpbmcgQ29uc3RhbnRzIEsgdGhlIHNhbWUgZm9yIGFsbA0KICAgIHNwcmluZ3M/Li4uKQ0KDQo4LiAgYERpcmVjdGVkIGFuZCB1bmRpcmVjdGVkIG5ldHdvcmsgZ3JhcGhgOiBJZiB0aGUgZGlzdGluY3Rpb24gYmV0d2Vlbg0KICAgIHNvdXJjZSBhbmQgdGFyZ2V0IGlzIG1lYW5pbmdmdWwsIHRoZSBuZXR3b3JrIGlzICoqZGlyZWN0ZWQuKiogSWYgdGhlDQogICAgZGlzdGluY3Rpb24gaXMgbm90IG1lYW5pbmdmdWwsIHRoZSBuZXR3b3JrIGlzICoqdW5kaXJlY3RlZCoqLg0KICAgICoqRGlyZWN0ZWQgZWRnZXMqKiByZXByZXNlbnQgYW4gb3JkZXJpbmcgb2Ygbm9kZXMsIGxpa2UgYQ0KICAgIHJlbGF0aW9uc2hpcCBleHRlbmRpbmcgZnJvbSBvbmUgbm9kZXMgdG8gYW5vdGhlciwgd2hlcmUgc3dpdGNoaW5nDQogICAgdGhlIGRpcmVjdGlvbiB3b3VsZCBjaGFuZ2UgdGhlIHN0cnVjdHVyZSBvZiB0aGUgbmV0d29yay4NCiAgICAqKlVuZGlyZWN0ZWQgZWRnZXMqKiBhcmUgc2ltcGx5IGxpbmtzIGJldHdlZW4gbm9kZXMgd2hlcmUgb3JkZXIgZG9lcw0KICAgIG5vdCBtYXR0ZXIuDQoNCkV4YW1wbGVzOg0KDQotIFRoZSBXb3JsZCBXaWRlIFdlYiBpcyBhbiBleGFtcGxlIG9mIGEgZGlyZWN0ZWQgbmV0d29yayBiZWNhdXNlDQpoeXBlcmxpbmtzIGNvbm5lY3Qgb25lIFdlYiBwYWdlIHRvIGFub3RoZXIsIGJ1dCBub3QgbmVjZXNzYXJpbHkgdGhlDQpvdGhlciB3YXkgYXJvdW5kLiANCg0KLSBDby1hdXRob3JzaGlwIG5ldHdvcmtzIHJlcHJlc2VudCBleGFtcGxlcyBvZg0KdW4tZGlyZWN0ZWQgbmV0d29ya3MsIHdoZXJlIG5vZGVzIGFyZSBhdXRob3JzIGFuZCB0aGV5IGFyZSBjb25uZWN0ZWQgYnkgYW4gZWRnZSBpZiB0aGV5IGhhdmUgd3JpdHRlbiBhIHB1YmxpY2F0aW9uIHRvZ2V0aGVyIA0KDQotIFdoZW4gcGVvcGxlIHNlbmQgZS1tYWlsIHRvIGVhY2ggb3RoZXIsIHRoZSBkaXN0aW5jdGlvbiBiZXR3ZWVuIHRoZSBzZW5kZXIgKHNvdXJjZSkgYW5kIHRoZSByZWNpcGllbnQgKHRhcmdldCkgaXMgY2xlYXJseSBtZWFuaW5nZnVsLCB0aGVyZWZvcmUgdGhlIG5ldHdvcmsgaXMgZGlyZWN0ZWQuDQoNCjkuICBgQ29ubmVjdGVkYCBhbmQgYERpc2Nvbm5lY3RlZGAgZ3JhcGhzOiBJZiB0aGVyZSBpcyAqc29tZSogcGF0aCBmcm9tDQogICAgKmFueSBub2RlKiB0byAqYW55IG90aGVyIG5vZGUqLCB0aGUgTmV0d29ya3MgaXMgc2FpZCB0byBiZQ0KICAgIENvbm5lY3RlZC4gRWxzZSwgRGlzY29ubmVjdGVkLg0KDQojIFByZWRpY3QvUnVuL0luZmVyIC0xDQoNCiMjIFVzaW5nIGB0aWR5Z3JhcGhgIGFuZCBgZ2dyYXBoYA0KDQpgdGlkeWdyYXBoYCBhbmQgYGdncmFwaGAgYXJlIG1vZGVybiBSIHBhY2thZ2VzIGZvciBuZXR3b3JrIGRhdGEuIEdyYXBoDQpEYXRhIHNldHVwIGFuZCBtYW5pcHVsYXRpb24gaXMgZG9uZSBpbiB0aWR5Z3JhcGggYW5kIGdyYXBoIHZpc3VhbGl6YXRpb24NCndpdGggZ2dyYXBoLg0KDQotICAgYHRpZHlncmFwaGAgRGF0YSAtXD4gIk5ldHdvcmsgT2JqZWN0IiBpbiBSLg0KLSAgIGBnZ3JhcGhgIE5ldHdvcmsgT2JqZWN0IC1cPiBQbG90cyB1c2luZyBhIGNob3NlbiBsYXlvdXQvYWxnby4NCg0KQm90aCBsZXZlcmFnZSB0aGUgcG93ZXIgb2YgKipgaWdyYXBoYCoqLCB3aGljaCBpcyB0aGUgKipCaWcgRGFkZHkqKiBvZg0KYWxsIG5ldHdvcmsgcGFja2FnZXMuIFdlIHdpbGwgYmUgdXNpbmcgdGhlIEdyZXkncyBBbmF0b215IGRhdGFzZXQgaW4gb3VyDQpmaXJzdCBmb3JheSBpbnRvIG5ldHdvcmtzLg0KDQojIyBTdGVwMS4gUmVhZCB0aGUgZGF0YQ0KDQpgYGB7ciAxLlJlYWQtZ3JleXMtYW5hdG9teS1kYXRhfQ0KZ3JleV9ub2RlcyA8LSByZWFkX2NzdigiLi9EYXRhL2dyZXlzLW5vZGVzLmNzdiIpDQpncmV5X2VkZ2VzIDwtIHJlYWRfY3N2KCIuL0RhdGEvZ3JleXMtZWRnZXMuY3N2IikNCmdyZXlfbm9kZXMNCmdyZXlfZWRnZXMNCmBgYA0KDQoqKlF1ZXN0aW9ucyBhbmQgSW5mZXJlbmNlcyoqOiBDaGVjayB0aGUgY29uc29sZSBvdXRwdXQgdGh1bWJuYWlsIGJlbG93LiBXaGF0IGRvZXMgZm9yIGV4YW1wbGUgYG5hbWUgPSBjb2xfY2hhcmFjdGVyYCBtZWFuPyBXaGF0IGF0dHJpYnV0ZXMgKGkuZS4gZXh0cmEgaW5mb3JtYXRpb24pIGFyZSBzZWVuIGZvciBOb2RlcyBhbmQgRWRnZXM/IFVuZGVyc3RhbmQgdGhlIGRhdGEgaW4gYm90aCBub2RlcyBhbmQgZWRnZXMgYXMgc2hvd24gaW4gdGhlIHNlY29uZCBhbmQgdGhpcmQgdGh1bWJuYWlscy4gV3JpdGUgc29tZSBjb21tZW50cyBhbmQgaW5mZXJlbmNlcyBoZXJlLg0KDQoNCg0KIyMgU3RlcCAyLkNyZWF0ZSBhIG5ldHdvcmsgb2JqZWN0IHVzaW5nIHRpZHlncmFwaDoNCg0KS2V5IGZ1bmN0aW9uOg0KDQotICAgYHRibF9ncmFwaCgpYDogKGFrYSAidGliYmxlIGdyYXBoIikuIEtleSBhcmd1bWVudHM6IGBub2Rlc2AsIGBlZGdlc2ANCiAgICBhbmQgYGRpcmVjdGVkYC4gTm90ZSB0aGlzIGlzIGEgdmVyeSB2ZXJzYXRpbGUgY29tbWFuZCBhbmQgY2FuIHRha2UNCiAgICBtYW55IGlucHV0IGZvcm1zLCBzdWNoIGFzIGRhdGEgc3RydWN0dXJlcyB0aGF0IHJlc3VsdCBmcm9tIG90aGVyDQogICAgcGFja2FnZXMuIFR5cGUgYD90YmxfZ3JhcGhgIGluIHRoZSBDb25zb2xlIGFuZCBzZWUgdGhlIGBVc2FnZWANCiAgICBzZWN0aW9uLg0KDQpgYGB7ciAyLkNyZWF0ZS1ncmV5cy1hbmF0b215LWdyYXBoLW9iamVjdH0NCmdhIDwtIHRibF9ncmFwaChub2RlcyA9IGdyZXlfbm9kZXMsIGVkZ2VzID0gZ3JleV9lZGdlcyxkaXJlY3RlZCA9IEZBTFNFKQ0KZ2ENCmBgYA0KDQoqKlF1ZXN0aW9ucyBhbmQgSW5mZXJlbmNlcyoqOiBXaGF0IGluZm9ybWF0aW9uIGRvZXMgdGhlIGdyYXBoIG9iamVjdCBjb250YWluPyBXaGF0IGF0dHJpYnV0ZXMgZG8gdGhlIG5vZGVzIGhhdmU/IFdoYXQgYWJvdXQgdGhlIGVkZ2VzPw0KDQoNCg0KIyMgU3RlcCAzLiBQbG90IHVzaW5nIGBnZ3JhcGhgDQoNCjNhLiBRdWljayBQbG90OiBgYXV0b2dyYXBoKClgIFRoaXMgaXMgdG8gY2hlY2sgcXVpY2tseSBpcyB0aGUgZGF0YSBpcyBpbXBvcnRlZCBwcm9wZXJseSBhbmQgdG8gZGVjaWRlIHVwb24gZ29pbmcgb24gdG8gYSBtb3JlIGVsYWJvcmF0ZSBwbG90dGluZy4NCg0KYGBge3IgM2EuQXV0by1ncmFwaC1ncmV5cy1hbmF0b215fQ0KYXV0b2dyYXBoKGdhKQ0KYGBgDQoNCioqUXVlc3Rpb25zIGFuZCBJbmZlcmVuY2VzKio6IERlc2NyaWJlIHRoaXMgZ3JhcGgsIGluIHNpbXBsZSB3b3JkcyBoZXJlLiBUcnkgdG8gdXNlIHNvbWUgb2YgdGhlIG5ldyBkb21haW4gd29yZHMgd2UgaGF2ZSBqdXN0IGFjcXVpcmVkOiBub2Rlcy9lZGdlcywgY29ubmVjdGVkL2Rpc2Nvbm5lY3RlZCwgZGlyZWN0ZWQvdW5kaXJlY3RlZC4NCg0KDQozYi4gTW9yZSBlbGFib3JhdGUgcGxvdA0KDQpLZXkgZnVuY3Rpb25zOg0KDQotICAgYGdncmFwaChsYXlvdXQgPSAiLi4uLi4uIilgOiBDcmVhdGUgY2xhc3NpYyBub2RlLWVkZ2UgZGlhZ3JhbXM7IGkuZS4NCiAgICBTZXRzIHVwIHRoZSBncmFwaC4gUmF0aGVyIGxpa2UgYGdncGxvdGAgZm9yIG5ldHdvcmtzIQ0KDQpUd28ga2luZHMgb2YgYGdlb21gOiBvbmUgc2V0IGZvciBub2RlcywgYW5kIGFub3RoZXIgZm9yIGVkZ2VzDQoNCi0gICBgZ2VvbV9ub2RlX3BvaW50KGFlcyguLi4uLikpYDogRHJhd3Mgbm9kZSBhcyAicG9pbnRzIi4gQWx0ZXJuYXRpdmVzDQogICAgYXJlIGBjaXJjbGUgLyBhcmNfYmFyIC8gdGlsZSAvIHZvcm9ub2lgLiBSZW1lbWJlciB0aGUgYGdlb21gcyB0aGF0DQogICAgd2UgaGF2ZSBzZWVuIGJlZm9yZSBpbiBHcmFtbWFyIG9mIEdyYXBoaWNzIQ0KDQotICAgYGdlb21fZWRnZV9saW5rKGFlcyguLi4uLikpYDogRHJhd3MgZWRnZXMgYXMgImxpbmtzIi4gQWx0ZXJuYXRpdmVzDQogICAgYXJlDQogICAgYGFyYyAvIGJlbmQgLyBlbGJvdyAvIGhpdmUgLyBsb29wIC8gcGFyYWxsZWwgLyBkaWFnb25hbCAvIHBvaW50IC8gc3BhbiAvdGlsZWAuDQoNCi0gICBgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gLi4uLi4uKSwgcmVwZWwgPSBUUlVFKWA6IEFkZHMgdGV4dA0KICAgIGxhYmVscyAobm9uLW92ZXJsYXBwaW5nKS4gQWx0ZXJuYXRpdmVzIGFyZSBgbGFiZWwgLy4uLmANCg0KLSAgIGBsYWJzKHRpdGxlID0gIi4uLi4iLCBzdWJ0aXRsZSA9ICIuLi4uIiwgY2FwdGlvbiA9ICIuLi4uIilgOiBDaGFuZ2UNCiAgICBtYWluIHRpdGxlcywgYXhpcyBsYWJlbHMgYW5kIGxlZ2VuZCB0aXRsZXMuIFdlIGtub3cgdGhpcyBmcm9tIG91cg0KICAgIHdvcmsgd2l0aCBgZ2dwbG90YC4NCg0KYGBge3IgM2IuR2dyYXBoLWdyZXlzLWFuYXRvbXl9DQoNCiMgV3JpdGUgQ29tbWVudHMgbmV4dCB0byBlYWNoIGxpbmUgDQojIEFib3V0IHdoYXQgdGhhdCBsaW5lIGRvZXMgZm9yIHRoZSBvdmVyYWxsIGdyYXBoDQoNCmdncmFwaChncmFwaCA9IGdhLCAgbGF5b3V0ID0gImtrIikgKw0KICAjDQogIA0KICBnZW9tX2VkZ2VfbGluayh3aWR0aCA9IDIsIGNvbG9yID0gInBpbmsiKSArDQogICMNCiAgDQogIGdlb21fbm9kZV9wb2ludCgNCiAgICBzaGFwZSA9IDIxLA0KICAgIHNpemUgPSA4LA0KICAgIGZpbGwgPSAiYmx1ZSIsDQogICAgY29sb3IgPSAiZ3JlZW4iLA0KICAgIHN0cm9rZSA9IDINCiAgKSArDQogICMNCiAgDQogIGxhYnModGl0bGUgPSAiV2hvbyBIb28hIE15IGZpcnN0IHNpbGx5IEdyZXkncyBBbmF0b215IGdyYXBoIGluIFIhIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJXaHkgZGlkIHRoZSBEZWFuIHB1dCBtZSBpbiB0aGlzIGNvdXJzZS4uLiIsDQogICAgICAgY2FwdGlvbiA9ICJCcm8sIHRoZXkgYXJlIGRvaW5nICoqY29vbCoqIHRoaW5ncyBpbiB0aGUgb3RoZXIgDQogICAgICAgY2xhc3Nlcy4uLiIpDQoNCmBgYA0KDQoqKlF1ZXN0aW9ucyBhbmQgSW5mZXJlbmNlcyoqOiBXaGF0IHBhcmFtZXRlcnMgaGF2ZSBiZWVuIGNoYW5nZWQgaGVyZSwgY29tcGFyZWQgdG8gdGhlIGVhcmxpZXIgZ3JhcGg/IFdoZXJlIGRvIHlvdSBzZWUgdGhlc2UgY2hhbmdlcyBpbiB0aGUgY29kZSBhYm92ZT8NCg0KDQoNCkxldCB1cyAqKlBsYXkqKiB3aXRoIHRoaXMgZ3JhcGggYW5kIHNlZSBpZiB3ZSBjYW4gbWFrZSBzb21lIHNtYWxsDQpjaGFuZ2VzLiBDb2xvdXI/IEZpbGw/IFdpZHRoPyBTaXplPyBTdHJva2U/IExhYnM/IE9mIGNvdXJzZSENCg0KYGBge3IgM2MuTW9kaWZ5LUdyZXlzLUFuYXRvbXktZ2dyYXBofQ0KIyBDaGFuZ2UgdGhlIHBhcmFtZXRlcnMgaW4gZWFjaCBvZiB0aGUgY29tbWFuZHMgaGVyZSB0byBuZXcgb25lcw0KIyBVc2UgZml4ZWQgdmFsdWVzIGZvciBjb2xvdXJzIG9yIHNpemVzLi4uZXRjLiANCg0KZ2dyYXBoKGdyYXBoID0gZ2EsICBsYXlvdXQgPSAia2siKSArIA0KICBnZW9tX2VkZ2VfbGluayh3aWR0aCA9IDIpICsgDQogIGdlb21fbm9kZV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gOCwgDQogICAgICAgICAgICAgICAgICBmaWxsID0gImJsdWUiLCANCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gImdyZWVuIiwgDQogICAgICAgICAgICAgICAgICBzdHJva2UgPSAyKSArDQogIGxhYnModGl0bGUgPSAiV2hvbyBIb28hIE15IG5leHQgc2lsbHkgR3JleSdzIEFuYXRvbXkgZ3JhcGggaW4gUiEiLA0KICAgICAgIHN1YnRpdGxlID0gIldoeSBkaWQgUmFtZXNoIHB1dCBtZSBpbiB0aGlzIGNvdXJzZS4uLiIsDQogICAgICAgY2FwdGlvbiA9ICJCcm8sIHRoZXkgYXJlIGRvaW5nIGNvb2wgdGhpbmdzIGluIHRoZSBvdGhlciANCiAgICAgICBjbGFzc2VzLi4uIikNCmBgYA0KDQoqKlF1ZXN0aW9ucyBhbmQgSW5mZXJlbmNlcyoqOiBXaGF0IGRpZCB0aGUgYHNoYXBlYCBwYXJhbWV0ZXIgYWNoaWV2ZT8gV2hhdCBhcmUgdGhlIHBvc3NpYmlsaXRpZXMgd2l0aCBgc2hhcGVgPyBIb3cgYWJvdXQgaW5jbHVkaW5nIGBhbHBoYWA/DQoNCg0KDQozYy4gQWVzdGhldGljIE1hcHBpbmcgZnJvbSBOb2RlIGFuZCBFZGdlIGF0dHJpYnV0ZSBjb2x1bW5zDQoNClVwIHRvIG5vdywgd2UgaGF2ZSAqKmFzc2lnbmVkKiogKnNwZWNpZmljIG51bWJlcnMqIHRvIGdlb21ldHJpYyBhZXN0aGV0aWNzIHN1Y2ggYXMgc2hhcGUgYW5kIHNpemUuIE5vdyB3ZSBhcmUgcmVhZHkgKCBtYXliZSA/KSBjaGFuZ2UgdGhlIG1lYW5pbmcgYW5kIHNpZ25pZmljYW5jZSBvZiB0aGUgZW50aXJlIGdyYXBoIGFuZCBlYWNoIGVsZW1lbnQgd2l0aGluIGl0LCBhbmQgdXNlICoqYWVzdGhldGljcyAvIG1ldGFwaG9yaWMgbWFwcGluZ3MqKiB0byBhY2hpZXZlIG5ldyBtZWFuaW5ncyBvciBpbnNpZ2h0cy4gTGV0IHVzIHRyeSB1c2luZyBgYWVzKClgIGluc2lkZSBlYWNoIGBnZW9tYCB0byBtYXAgYSBgdmFyaWFibGVgIHRvIGEgZ2VvbWV0cmljIGFzcGVjdC4NCg0KRG9uJ3QgdHJ5IHRvIHVzZSBtb3JlIHRoYW4gMiBhZXN0aGV0aWMgbWFwcGluZ3Mgc2ltdWx0YW5lb3VzbHkhIQ0KDQpUaGUgbm9kZSBlbGVtZW50cyB3ZSBjYW4gdHdlYWsgYXJlOiANCg0KLSBUeXBlcyBvZiBOb2RlczogYGdlb21fbm9kZV8qKioqKClgICANCi0gTm9kZSBQYXJhbWV0ZXJzOiBpbnNpZGUgYGdlb21fbm9kZV8qKioqKGFlcyguLi4uLi4uLi4uLi4uLi4pKWAgIA0KLWBhZXMoYWxwaGEgID0gbm9kZS12YXJpYWJsZSlgIDogb3BhY2l0eTsgYSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDEgICANCi1gYWVzKHNoYXBlICA9IG5vZGUtdmFyaWFibGUpYCA6IG5vZGUgc2hhcGUgICANCi1gYWVzKGNvbG91ciA9IG5vZGUtdmFyaWFibGUpYCA6IG5vZGUgY29sb3VyICAgDQotYGFlcyhmaWxsICAgPSBub2RlLXZhcmlhYmxlKWAgOiBmaWxsIGNvbG91ciBmb3Igbm9kZSAgIA0KLWBhZXMoc2l6ZSAgID0gbm9kZS12YXJpYWJsZSlgIDogc2l6ZSBvZiBub2RlICANCg0KVGhlIGVkZ2UgZWxlbWVudHMgd2UgY2FuIHR3ZWFrIGFyZTogDQoNCi0gVHlwZSBvZiBFZGdlcyIgYGdlb21fZWRnZV8qKioqKClgICANCi0gRWRnZSBQYXJhbWV0ZXJzOiBpbnNpZGUgYGdlb21fZWRnZV8qKioqKGFlcyguLi4uLi4uLi4uLi4uLi4pKWAgICANCi1gYWVzKGNvbG91ciA9IGVkZ2UtdmFyaWFibGUpYCA6IGNvbG91ciBvZiB0aGUgZWRnZSAgIA0KLWBhZXMod2lkdGggID0gZWRnZS12YXJpYWJsZSlgIDogd2lkdGggb2YgdGhlIGVkZ2UgICANCi1gYWVzKGxhYmVsICA9IHNvbWVfdmFyaWFibGUpYCA6IGxhYmVscyBmb3IgdGhlIGVkZ2UgIA0KDQpUeXBlID9nZW9tX25vZGVfcG9pbnQgYW5kID9nZW9tLWVkZ2VfbGluayBpbiB5b3VyIENvbnNvbGUgZm9yIG1vcmUNCmluZm9ybWF0aW9uLg0KDQpgYGB7ciAzZC5hZXN0aGV0aWNzLXVzaW5nLWdncmFwaC1Nb2RpZnl9DQoNCmdncmFwaChncmFwaCA9IGdhLCBsYXlvdXQgPSAiZnIiKSArDQogIGdlb21fZWRnZV9saW5rMCgpICsgIyBhZGQgbWFwcGluZyBoZXJlDQogIA0KICBnZW9tX25vZGVfcG9pbnQoKSArICMgYWRkIG1hcHBpbmcgaGVyZQ0KDQogIGdlb21fbm9kZV9sYWJlbChhZXMobGFiZWwgPSBuYW1lKSwgIyBtb2RpZnkgdGhpcyBtYXBwaW5nDQogICAgICAgICAgICAgICAgICByZXBlbCA9IFRSVUUsIG1heC5vdmVybGFwcyA9IDIwLA0KICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjYsDQogICAgICAgICAgICAgICAgICBzaXplID0gMykgKw0KICANCiAgbGFicyh0aXRsZSA9ICJXaG9vIEhvbyEgWWV0IGFub3RoZXIgR3JleSdzIEFuYXRvbXkgZ3JhcGggaW4gUiEiKQ0KYGBgDQoNCioqUXVlc3Rpb25zIGFuZCBJbmZlcmVuY2VzKio6IERlc2NyaWJlIHNvbWUgb2YgdGhlIGNoYW5nZXMgaGVyZS4gV2hhdCB0eXBlcyBvZiBlZGdlcyB3b3JrZWQ/IFdoaWNoIHZhcmlhYmxlcyB3ZXJlIHlvdSBhYmxlIHRvIHVzZSBmb3Igbm9kZXMgYW5kIGVkZ2VzIGFuZCBob3c/IFdoYXQgZGlkIG5vdCB3b3JrIHdpdGggZWl0aGVyIG9mIHRoZSB0d28/DQoNCg0KDQoNCiMgUHJlZGljdC9SZXVzZS9JbmZlci0yDQoNCmBgYHtyIGFyYy1kaWFncmFtfQ0KIyBBcmMgZGlhZ3JhbQ0KZ2dyYXBoKGdhLCBsYXlvdXQgPSAibGluZWFyIikgKw0KICBnZW9tX2VkZ2VfYXJjKGFlcyh3aWR0aCA9IHdlaWdodCksIGFscGhhID0gMC44KSArDQogIHNjYWxlX2VkZ2Vfd2lkdGgocmFuZ2UgPSBjKDAuMiwgMikpICsNCiAgZ2VvbV9ub2RlX3BvaW50KHNpemUgPSAyLCBjb2xvdXIgPSAicmVkIikgKw0KICBsYWJzKGVkZ2Vfd2lkdGggPSAiV2VpZ2h0IikgKw0KICB0aGVtZV9ncmFwaCgpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikNCmBgYA0KDQoqKlF1ZXN0aW9ucyBhbmQgSW5mZXJlbmNlcyoqOiBIb3cgZG9lcyB0aGlzIGdyYXBoIGxvb2sgIm1ldGFwaG9yaWNhbGx5IiBkaWZmZXJlbnQ/IERvIHlvdSBzZWUgYSBkaWZmZXJlbmNlIGluIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gcGVvcGxlIGhlcmU/IFdoeT8NCg0KDQoNCmBgYHtyIENvb3JkLURpYWdyYW0tY2lyY3VsYXJ9DQojIENvb3JkIGRpYWdyYW0sIGNpcmN1bGFyDQpnZ3JhcGgoZ2EsIGxheW91dCA9ICJsaW5lYXIiLCBjaXJjdWxhciA9IFRSVUUpICsgDQogIGdlb21fZWRnZV9hcmMoYWVzKHdpZHRoID0gd2VpZ2h0KSwgYWxwaGEgPSAwLjgpICsgDQogIHNjYWxlX2VkZ2Vfd2lkdGgocmFuZ2UgPSBjKDAuMiwgMikpICsNCiAgZ2VvbV9ub2RlX3BvaW50KHNpemUgPSA0LGNvbG91ciA9ICJyZWQiKSArIA0KICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSxyZXBlbCA9IFRSVUUsIHNpemUgPSAzLA0KICAgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAyMCkgKw0KICBsYWJzKGVkZ2Vfd2lkdGggPSAiV2VpZ2h0IikgKw0KICB0aGVtZV9ncmFwaCgpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCANCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkNCmBgYA0KDQoqKlF1ZXN0aW9ucyBhbmQgSW5mZXJlbmNlcyoqOiBIb3cgZG9lcyB0aGlzIGdyYXBoIGxvb2sgIm1ldGFwaG9yaWNhbGx5IiBkaWZmZXJlbnQ/IERvIHlvdSBzZWUgYSBkaWZmZXJlbmNlIGluIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gcGVvcGxlIGhlcmU/IFdoeT8NCg0KDQoNCiMgSGllcmFyY2hpY2FsIGxheW91dHMNCg0KVGhlc2UgcHJvdmlkZSBmb3Igc29tZSBhbHRlcm5hdGl2ZSBtZXRhcGhvcmljYWwgdmlld3Mgb2YgbmV0d29ya3MuIE5vdGUgdGhhdCBub3QgYWxsIGxheW91dHMgYXJlIHBvc3NpYmxlIGZvciBhbGwgZGF0YXNldHMhIQ0KDQpgYGB7cn0NCiMgc2V0dGluZyB0aGVtZV9ncmFwaCANCnNldF9ncmFwaF9zdHlsZSgpDQoNCiMgVGhpcyBkYXRhc2V0IGNvbnRhaW5zIHRoZSBncmFwaCB0aGF0IGRlc2NyaWJlcyB0aGUgY2xhc3MgDQojIGhpZXJhcmNoeSBmb3IgdGhlIEZsYXJlIHZpc3VhbGl6YXRpb24gbGlicmFyeS4NCiMgVHlwZSA/ZmxhcmUgaW4geW91ciBDb25zb2xlDQpoZWFkKGZsYXJlJHZlcnRpY2VzKQ0KaGVhZChmbGFyZSRlZGdlcykNCg0KIyBmbGFyZSBjbGFzcyBoaWVyYXJjaHkNCmdyYXBoID0gdGJsX2dyYXBoKGVkZ2VzID0gZmxhcmUkZWRnZXMsIG5vZGVzID0gZmxhcmUkdmVydGljZXMpDQoNCiMgZGVuZHJvZ3JhbQ0KZ2dyYXBoKGdyYXBoLCBsYXlvdXQgPSAiZGVuZHJvZ3JhbSIpICsgDQogIGdlb21fZWRnZV9kaWFnb25hbCgpICsgDQogIGxhYnModGl0bGUgPSAiRGVuZHJvZ3JhbSIpDQoNCiMgY2lyY3VsYXIgZGVuZHJvZ3JhbQ0KZ2dyYXBoKGdyYXBoLCBsYXlvdXQgPSAiZGVuZHJvZ3JhbSIsIGNpcmN1bGFyID0gVFJVRSkgKyANCiAgZ2VvbV9lZGdlX2RpYWdvbmFsKCkgKyANCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhmaWx0ZXIgPSBsZWFmKSkgKyANCiAgY29vcmRfZml4ZWQoKSsgDQogIGxhYnModGl0bGUgPSAiQ2lyY3VsYXIgRGVuZHJvZ3JhbSIpDQoNCiMgcmVjdGFuZ3VsYXIgdHJlZSBtYXANCmdncmFwaChncmFwaCwgbGF5b3V0ID0gInRyZWVtYXAiLCB3ZWlnaHQgPSBzaXplKSArIA0KICBnZW9tX25vZGVfdGlsZShhZXMoZmlsbCA9IGRlcHRoKSwgc2l6ZSA9IDAuMjUpICsgDQogIGxhYnModGl0bGUgPSAiUmVjdGFuZ3VsYXIgVHJlZSBNYXAiKQ0KDQojIGNpcmN1bGFyIHRyZWUgbWFwDQpnZ3JhcGgoZ3JhcGgsIGxheW91dCA9ICJjaXJjbGVwYWNrIiwgd2VpZ2h0ID0gc2l6ZSkgKyANCiAgZ2VvbV9ub2RlX2NpcmNsZShhZXMoZmlsbCA9IGRlcHRoKSwgc2l6ZSA9IDAuMjUsIG4gPSA1MCkgKyANCiAgY29vcmRfZml4ZWQoKSArIA0KICBsYWJzKHRpdGxlID0gIkNpcmN1bGFyIFRyZWUgTWFwIikNCg0KIyBpY2ljbGUNCmdncmFwaChncmFwaCwgbGF5b3V0ID0gInBhcnRpdGlvbiIpICsgDQogIGdlb21fbm9kZV90aWxlKGFlcyh5ID0gLXksIGZpbGwgPSBkZXB0aCkpDQoNCiMgc3VuYnVyc3QgKGNpcmN1bGFyIGljaWNsZSkNCmdncmFwaChncmFwaCwgbGF5b3V0ID0gInBhcnRpdGlvbiIsIGNpcmN1bGFyID0gVFJVRSkgKw0KICBnZW9tX25vZGVfYXJjX2JhcihhZXMoZmlsbCA9IGRlcHRoKSkgKw0KICBjb29yZF9maXhlZCgpICsgDQogIGxhYnModGl0bGUgPSAiQ2lyY3VsYXIgSWNpY2xlIikNCmBgYA0KDQoqKlF1ZXN0aW9ucyBhbmQgSW5mZXJlbmNlcyoqOiBIb3cgZG8gZ3JhcGhzIGxvb2sgIm1ldGFwaG9yaWNhbGx5IiBkaWZmZXJlbnQ/IERvIHRoZXkgcmV2ZWFsIGRpZmZlcmVudCBhc3BlY3RzIG9mIHRoZSBncm91cD8gSG93Pw0KDQoNCg0KDQoNCg0KIyBGYWNldGluZw0KDQpGYWNldGluZyBhbGxvd3MgdG8gY3JlYXRlIHN1Yi1wbG90cyBhY2NvcmRpbmcgdG8gdGhlIHZhbHVlcyBvZiBhDQpxdWFsaXRhdGl2ZSBhdHRyaWJ1dGUgb24gbm9kZXMgb3IgZWRnZXMuDQoNCmBgYHtyIGZhY2V0aW5nfQ0KIyBzZXR0aW5nIHRoZW1lX2dyYXBoIA0Kc2V0X2dyYXBoX3N0eWxlKCkNCg0KDQojIGZhY2V0IGVkZ2VzIGJ5IHR5cGUNCmdncmFwaChnYSxsYXlvdXQgPSAibGluZWFyIiwgY2lyY3VsYXIgPSBUUlVFKSArIA0KICBnZW9tX2VkZ2VfbGluayhhZXMoY29sb3IgPSB0eXBlKSkgKyANCiAgZ2VvbV9ub2RlX3BvaW50KCkgKw0KICBmYWNldF9lZGdlcyh+IHR5cGUpDQoNCiMgZmFjZXQgbm9kZXMgYnkgc2V4DQpnZ3JhcGgoZ2EsbGF5b3V0ID0gImxpbmVhciIsIGNpcmN1bGFyID0gVFJVRSkgKyANCiAgZ2VvbV9lZGdlX2xpbmsoKSArIA0KICBnZW9tX25vZGVfcG9pbnQoKSArDQogIGZhY2V0X25vZGVzKH5yYWNlKQ0KDQojIGZhY2V0IGJvdGggbm9kZXMgYW5kIGVkZ2VzDQpnZ3JhcGgoZ2EsbGF5b3V0ID0gImxpbmVhciIsIGNpcmN1bGFyID0gVFJVRSkgKyANCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKGNvbG9yID0gdHlwZSkpICsgDQogIGdlb21fbm9kZV9wb2ludCgpICsNCiAgZmFjZXRfZ3JhcGgodHlwZSB+IHJhY2UpICsgDQogIHRoX2ZvcmVncm91bmQoYm9yZGVyID0gVFJVRSkNCmBgYA0KDQoqKlF1ZXN0aW9ucyBhbmQgSW5mZXJlbmNlcyoqOiBEb2VzIHNwbGl0dGluZyB1cCB0aGUgbWFpbiBncmFwaCBpbnRvIHN1Ym5ldHdvcmtzIGdpdmUgeW91IG1vcmUgaW5zaWdodD8gRGVzY3JpYmUgc29tZSBvZiB0aGVzZS4NCg0KDQoNCg0KDQoNCiMgTmV0d29yayBhbmFseXNpcyB3aXRoIHRpZHlncmFwaA0KDQpUaGUgZGF0YSBmcmFtZSBncmFwaCByZXByZXNlbnRhdGlvbiBjYW4gYmUgZWFzaWx5IGF1Z21lbnRlZCB3aXRoICoqbWV0cmljcyoqIG9yICoqc3RhdGlzdGljcyoqIGNvbXB1dGVkIG9uIHRoZSBncmFwaC4gUmVtZW1iZXIgaG93IHdlIGNvbXB1dGVkIGBjb3VudHNgIHdpdGggdGhlIHBlbmd1aW4gZGF0YXNldCBpbiBHcmFtbWFyIG9mIEdyYXBoaWNzLiBCZWZvcmUgY29tcHV0aW5nIGEgbWV0cmljIG9uIG5vZGVzIG9yIGVkZ2VzIHVzZSB0aGUgYGFjdGl2YXRlKClgIGZ1bmN0aW9uIHRvIGFjdGl2YXRlIGVpdGhlciBub2RlIG9yIGVkZ2UgZGF0YSBmcmFtZXMuIFVzZSBgZHBseXJgICoqdmVyYnMqKiAoYGZpbHRlciwgYXJyYW5nZSwgbXV0YXRlYCkgdG8gYWNoaWV2ZSB5b3VyIGNvbXB1dGF0aW9uIGluIHRoZSBwcm9wZXIgd2F5Lg0KDQoNCg0KIyMgTmV0d29yayBDZW50cmFsaXR5DQoNCkNlbnRyYWxpdHkgaXMgYSBhbiAiaWxsLWRlZmluZWQiIG1ldHJpYyBvZiAqKm5vZGUgYW5kIGVkZ2UgaW1wb3J0YW5jZSoqIGluIGEgbmV0d29yay4gSXQgaXMgdGhlcmVmb3JlIGNhbGN1bGF0ZWQgaW4gbWFueSB3YXlzLiBUeXBlIGA/Y2VudHJhbGl0eWAgaW4geW91ciBDb25zb2xlLg0KDQohW1N0YW5kYXJkc10oaHR0cHM6Ly9pbWdzLnhrY2QuY29tL2NvbWljcy9zdGFuZGFyZHMucG5nLGFsaWduID0gImNlbnRlcikNCg0KDQpMZXQncyBhZGQgYSBmZXcgY29sdW1ucyB0byB0aGUgbm9kZXMgYW5kIGVkZ2VzIGJhc2VkIG9uIG5ldHdvcmsgY2VudHJhbGl0eSBtZWFzdXJlczoNCg0KDQpgYGB7ciBuZXR3b3JrLWFuYWx5c2lzLTF9DQpnYSAlPiUgDQogIGFjdGl2YXRlKG5vZGVzKSAlPiUgDQogIA0KICAjIE1vc3QgY29ubmVjdGlvbnM/DQogIG11dGF0ZShkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZSgpKSAlPiUgDQogIGZpbHRlcihkZWdyZWUgPiAwKSAlPiUgDQogIGFjdGl2YXRlKGVkZ2VzKSAlPiUgDQogIA0KICAjICJCdXNpZXN0IiBlZGdlPw0KICBtdXRhdGUoYmV0d2Vlbm5lc3MgPSBjZW50cmFsaXR5X2VkZ2VfYmV0d2Vlbm5lc3MoKSANCiAgICAgICAgICkNCmBgYA0KDQpQYWNrYWdlcyBgdGlkeWdyYXBoYCBhbmQgYGdncmFwaGAgY2FuIGJlIHBpcGVsaW5lZCB0byBwZXJmb3JtIGFuYWx5c2lzIGFuZCB2aXN1YWxpemF0aW9uIHRhc2tzIGluIG9uZSBnby4NCg0KYGBge3IgVXNpbmctQ2VudHJhbGl0eX0NCiMgc2V0dGluZyB0aGVtZV9ncmFwaCANCnNldF9ncmFwaF9zdHlsZSgpDQoNCmdhICU+JSANCiAgYWN0aXZhdGUobm9kZXMpICU+JSANCiAgDQogICMgV2hvIGhhcyB0aGUgbW9zdCBjb25uZWN0aW9ucz8NCiAgbXV0YXRlKGRlZ3JlZSA9IGNlbnRyYWxpdHlfZGVncmVlKCkpICU+JSANCiAgYWN0aXZhdGUoZWRnZXMpICU+JSANCiAgDQogICMgV2hvIGlzIHRoZSBnby10aHJvdWdoIHBlcnNvbj8NCiAgbXV0YXRlKGJldHdlZW5uZXNzID0gY2VudHJhbGl0eV9lZGdlX2JldHdlZW5uZXNzKCkpICU+JQ0KICANCiAgIyBOb3cgdG8gY29udGludWUgd2l0aCBwbG90dGluZw0KICBnZ3JhcGgobGF5b3V0ID0gIm5pY2VseSIpICsNCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKGFscGhhID0gYmV0d2Vlbm5lc3MpKSArDQogIGdlb21fbm9kZV9wb2ludChhZXMoc2l6ZSA9IGRlZ3JlZSwgY29sb3VyID0gZGVncmVlKSkgKyANCiAgDQogICMgZGlzY3JldGUgY29sb3VyIGxlZ2VuZA0KICBzY2FsZV9jb2xvcl9ncmFkaWVudChndWlkZSA9ICJsZWdlbmQiKQ0KDQojIG9yIGV2ZW4gbGVzcyB0eXBpbmcNCiAgZ2dyYXBoKGdhLGxheW91dCA9ICJuaWNlbHkiKSArDQogIGdlb21fZWRnZV9saW5rKGFlcyhhbHBoYSA9IGNlbnRyYWxpdHlfZWRnZV9iZXR3ZWVubmVzcygpKSkgKw0KICBnZW9tX25vZGVfcG9pbnQoYWVzKGZpbGwgPSBjZW50cmFsaXR5X2RlZ3JlZSgpLCANCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBjZW50cmFsaXR5X2RlZ3JlZSgpKSkgKyANCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQoZ3VpZGUgPSAibGVnZW5kIiwNCiAgICAgICAgICAgICAgICAgICAgICAgbG93ID0gImdyZWVuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJyZWQiKQ0KYGBgDQoNCiMjIEFuYWx5c2UgYW5kIHZpc3VhbGl6ZSBuZXR3b3JrOiBjb21tdW5pdGllcw0KDQpgYGB7cn0NCiMgc2V0dGluZyB0aGVtZV9ncmFwaCANCnNldF9ncmFwaF9zdHlsZSgpDQoNCg0KIyB2aXN1YWxpemUgY29tbXVuaXRpZXMgb2Ygbm9kZXMNCmdhICU+JSANCiAgI21ha2VfdW5kaXJlY3RlZF9ncmFwaCgpICU+JSANCiAgI2FjdGl2YXRlKGVkZ2VzKSAlPiUgbXV0YXRlKGZyb20gPSBhcy5udW1lcmljKGZyb20pLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICB0byA9IGFzLm51bWVyaWModG8pKSAlPiUgDQogIGFjdGl2YXRlKG5vZGVzKSAlPiUNCiAgbXV0YXRlKGNvbW11bml0eSA9IGFzLmZhY3Rvcihncm91cF9sb3V2YWluKCkpKSAlPiUgDQogIGdncmFwaChsYXlvdXQgPSAiZ3JhcGhvcHQiKSArIA0KICBnZW9tX2VkZ2VfbGluaygpICsgDQogIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3IgPSBjb21tdW5pdHkpLCBzaXplID0gNSkNCg0KYGBgDQoNCkdvb2QsIHlvdSBhcmUgbm93IGEgZ1JhcGhpc3RhICEhDQoNCg0KIyBCb251cyBNYXRlcmlhbCBmb3IgdGhlIEludHJlcGlkDQoNCkV4cGxvcmluZyB0aGUgYFZpc05ldHdvcmtgIHBhY2thZ2UuIE1ha2UgZ3JhcGhzIHdpZ2dsZSBhbmQgc2hha2UgdXNpbmcgYHRpZHlgIGNvbW1hbmRzIQ0KDQpUaGUgYHZpc05ldHdvcmsoKWAgZnVuY3Rpb24gdXNlcyBhIG5vZGVzIGxpc3QgYW5kIGVkZ2VzIGxpc3QgdG8gY3JlYXRlIGFuIGludGVyYWN0aXZlIGdyYXBoLiBUaGUgbm9kZXMgbGlzdCBtdXN0IGluY2x1ZGUgYW4gImlkIiBjb2x1bW4sIGFuZCB0aGUgZWRnZSBsaXN0IG11c3QgaGF2ZSAiZnJvbSIgYW5kICJ0byIgY29sdW1ucy4gVGhlIGZ1bmN0aW9uIGFsc28gcGxvdHMgdGhlIGxhYmVscyBmb3IgdGhlIG5vZGVzLCB1c2luZyB0aGUgbmFtZXMgb2YgdGhlIGNpdGllcyBmcm9tIHRoZSAibGFiZWwiIGNvbHVtbiBpbiB0aGUgbm9kZSBsaXN0Lg0KDQpgYGB7ciBncmV5cy1hbmF0b215LWRhdGEtZm9yLXZpc25ldHdvcmt9DQpsaWJyYXJ5KHZpc05ldHdvcmspDQoNCiMgUHJlcGFyZSB0aGUgZGF0YSBmb3IgcGxvdHRpbmcgYnkgdmlzTmV0d29yaw0KZ3JleV9ub2Rlcw0KZ3JleV9lZGdlcw0KDQojIFJlbGFiZWwgZ3JleXMgYW5hdG9teSBub2RlcyBhbmQgZWRnZXMgZm9yIFZpc05ldHdvcmsNCmdyZXlfbm9kZXNfdmlzIDwtIGdyZXlfbm9kZXMgJT4lIA0KICByb3dpZF90b19jb2x1bW4odmFyID0gImlkIikgJT4lIA0KICByZW5hbWUoImxhYmVsIiA9IG5hbWUpICU+JSANCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXggPT0gIkYiIH4gIkZlbWFsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgc2V4ID09ICJNIiB+ICJNYWxlIikpICU+JSANCiAgcmVwbGFjZV9uYSguLCBsaXN0KHNleCA9ICJUcmFuc2dlbmRlcj8iKSkgJT4lIA0KICByZW5hbWUoImdyb3VwIiA9IHNleCkNCmdyZXlfbm9kZXNfdmlzDQpncmV5X2VkZ2VzX3ZpcyA8LSBncmV5X2VkZ2VzICU+JSANCiAgc2VsZWN0KGZyb20sIHRvKSAlPiUgDQogIGxlZnRfam9pbiguLCBncmV5X25vZGVzX3ZpcywgYnkgPSBjKCJmcm9tIiA9ICJsYWJlbCIpKSAlPiUgDQogIGxlZnRfam9pbiguLCBncmV5X25vZGVzX3ZpcywgYnkgPSBjKCJ0byIgPSAibGFiZWwiKSkgJT4lDQogIHNlbGVjdCgiZnJvbSI9IGlkLngsICJ0byIgPSBpZC55KQ0KZ3JleV9lZGdlc192aXMNCmBgYA0KDQpVc2luZyBbZm9udGF3ZXNvbWUgaWNvbnNdKGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tL3Y2LjAvaWNvbnMpDQoNCmBgYHtyIGdyZXlzLWFuYXRvbXktdmlzTmV0d29ya30NCmdyZXlfbm9kZXNfdmlzICU+JQ0KDQogIHZpc05ldHdvcmsobm9kZXMgPSAuLCBlZGdlcyA9IGdyZXlfZWRnZXNfdmlzKSAlPiUgDQogIHZpc05vZGVzKGZvbnQgPSBsaXN0KHNpemUgPSA0MCkpICU+JSANCiAgDQogICMgQ29sb3VyIGFuZCBpY29ucyBmb3IgZWFjaCBvZiB0aGUgZ2VuZGVyLWdyb3Vwcw0KICB2aXNHcm91cHMoZ3JvdXBuYW1lID0gIkZlbWFsZSIsIHNoYXBlID0gImljb24iLCANCiAgICAgICAgICAgIGljb24gPSBsaXN0KGNvZGUgPSAiZjE4MiIsIHNpemUgPSA3NSwgY29sb3IgPSAidG9tYXRvIiksDQogICAgICAgICAgICBzaGFkb3cgPSBsaXN0KGVuYWJsZWQgPSBUUlVFKSkgJT4lIA0KICANCiAgdmlzR3JvdXBzKGdyb3VwbmFtZSA9ICJNYWxlIiwgc2hhcGUgPSAiaWNvbiIsIA0KICAgICAgICAgICAgaWNvbiA9IGxpc3QoY29kZSA9ICJmMTgzIiwgc2l6ZSA9IDc1LCBjb2xvciA9ICJzbGF0ZWJsdWUiKSwgDQogICAgICAgICAgICBzaGFkb3cgPSBsaXN0KGVuYWJsZWQgPSBUUlVFKSkgJT4lIA0KICANCiAgdmlzR3JvdXBzKGdyb3VwbmFtZSA9ICJUcmFuc2dlbmRlcj8iLCBzaGFwZSA9ICJpY29uIiwgDQogICAgICAgICAgICBpY29uID0gbGlzdChjb2RlID0gImYyMmMiLCBzaXplID0gNzUsIGNvbG9yID0gImZ1Y2hzaWEiKSwgDQogICAgICAgICAgICBzaGFkb3cgPSBsaXN0KGVuYWJsZWQgPSBUUlVFKSkgJT4lIA0KICANCiAgI3Zpc0xlZ2VuZCgpICU+JQ0KICAjQWRkIHRoZSBmb250YXdlc29tZSBpY29ucyEhDQogIGFkZEZvbnRBd2Vzb21lKCkgJT4lIA0KICANCiAgIyBBZGQgSW50ZXJhY3Rpb24gQ29udHJvbHMNCiAgdmlzSW50ZXJhY3Rpb24obmF2aWdhdGlvbkJ1dHRvbnMgPSBUUlVFLA0KICAgICAgICAgICAgICAgICBob3ZlciA9IFRSVUUsDQogICAgICAgICAgICAgICAgIHNlbGVjdENvbm5lY3RlZEVkZ2VzID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgaG92ZXJDb25uZWN0ZWRFZGdlcyA9IFRSVUUsDQogICAgICAgICAgICAgICAgIHpvb21WaWV3ID0gVFJVRSkNCmBgYA0KDQpUaGVyZSBpcyBhbm90aGVyIGZhbWlseSBvZiBpY29ucyBhdmFpbGFibGUgaW4gdmlzTmV0d29yaywgY2FsbGVkIFtgaW9uaWNvbnNgXShodHRwczovL3VucGtnLmNvbS9pb25pY29uc0A1LjUuMi9kaXN0L2NoZWF0c2hlZXQuaHRtbCkuIExldCdzIHNlZSBob3cgdGhleSBsb29rOg0KDQpgYGB7ciB1c2luZy1pb25pY29uc30NCmdyZXlfbm9kZXNfdmlzICU+JQ0KDQogIHZpc05ldHdvcmsobm9kZXMgPSAuLCBlZGdlcyA9IGdyZXlfZWRnZXNfdmlzLCkgJT4lDQogIHZpc0xheW91dChyYW5kb21TZWVkID0gMTIzNDUpICU+JQ0KICB2aXNOb2Rlcyhmb250ID0gbGlzdChzaXplID0gNTApKSAlPiUNCiAgdmlzRWRnZXMoY29sb3IgPSAiZ3JlZW4iKSAlPiUNCiAgdmlzR3JvdXBzKA0KICAgIGdyb3VwbmFtZSA9ICJGZW1hbGUiLA0KICAgIHNoYXBlID0gImljb24iLA0KICAgIGljb24gPSBsaXN0KA0KICAgICAgZmFjZSA9ICdJb25pY29ucycsDQogICAgICBjb2RlID0gImYyNWQiLA0KICAgICAgY29sb3IgPSAiZnVjaHNpYSIsDQogICAgICBzaXplID0gMTI1DQogICAgKQ0KICApICU+JQ0KICANCiAgdmlzR3JvdXBzKA0KICAgIGdyb3VwbmFtZSA9ICJNYWxlIiwNCiAgICBzaGFwZSA9ICJpY29uIiwNCiAgICBpY29uID0gbGlzdCgNCiAgICAgIGZhY2UgPSAnSW9uaWNvbnMnLA0KICAgICAgY29kZSA9ICJmMjAyIiwNCiAgICAgIGNvbG9yID0gImdyZWVuIiwNCiAgICAgIHNpemUgPSAxMjUNCiAgICApDQogICkgJT4lDQogIA0KICB2aXNHcm91cHMoDQogICAgZ3JvdXBuYW1lID0gIlRyYW5zZ2VuZGVyPyIsDQogICAgc2hhcGUgPSAiaWNvbiIsDQogICAgaWNvbiA9IGxpc3QoDQogICAgICBmYWNlID0gJ0lvbmljb25zJywNCiAgICAgIGNvZGUgPSAiZjIzMyIsDQogICAgICBjb2xvciA9ICJkb2RnZXJibHVlIiwNCiAgICAgIHNpemUgPSAxMjUNCiAgICApDQogICkgJT4lDQogIHZpc0xlZ2VuZCgpICU+JQ0KICBhZGRJb25pY29ucygpICU+JQ0KICB2aXNJbnRlcmFjdGlvbigNCiAgICBuYXZpZ2F0aW9uQnV0dG9ucyA9IFRSVUUsDQogICAgaG92ZXIgPSBUUlVFLA0KICAgIHNlbGVjdENvbm5lY3RlZEVkZ2VzID0gVFJVRSwNCiAgICBob3ZlckNvbm5lY3RlZEVkZ2VzID0gVFJVRSwNCiAgICB6b29tVmlldyA9IFRSVUUNCiAgKQ0KYGBgDQoNCg0KU29tZSBpZGVhIG9mIGludGVyYWN0aXZpdHkgYW5kIGNvbnRyb2xzIHdpdGggYHZpc05ldHdvcmtgOg0KDQpgYGB7ciB2aXNOZXR3b3JrLXN0YXJ3YXJzLTF9DQpsaWJyYXJ5KHZpc05ldHdvcmspDQojIGxldCdzIGxvb2sgYWdhaW4gYXQgdGhlIGRhdGENCnN0YXJ3YXJzX25vZGVzIDwtIHJlYWRfY3N2KCIuL0RhdGEvc3Rhci13YXJzLW5ldHdvcmstbm9kZXMuY3N2IikNCnN0YXJ3YXJzX2VkZ2VzIDwtIHJlYWRfY3N2KCIuL0RhdGEvc3Rhci13YXJzLW5ldHdvcmstZWRnZXMuY3N2IikNCg0KYGBgDQoNCmBgYHtyIHZpc05ldHdvcmstc3RhcndhcnMtMn0NCiMgV2UgbmVlZCB0byByZW5hbWUgc3RhcndhcnMgbm9kZXMgZGF0YWZyYW1lIGFuZCBlZGdlIGRhdGFmcmFtZSBjb2x1bW5zIGZvciB2aXNOZXR3b3JrDQpzdGFyd2Fyc19ub2Rlc192aXMgPC0gDQogIHN0YXJ3YXJzX25vZGVzICU+JSANCiAgcmVuYW1lKCJsYWJlbCIgPSBuYW1lKQ0KDQojIENvbnZlcnQgZnJvbSBhbmQgdG8gY29sdW1ucyB0byAqKm5vZGUgaWRzKioNCnN0YXJ3YXJzX2VkZ2VzX3ZpcyA8LSANCiAgc3RhcndhcnNfZWRnZXMgJT4lIA0KICANCiAgIyBNYXRjaGluZyBTb3VyY2UgPC0gU291cmNlIE5vZGUgaWQgKCJpZC54IikNCiAgbGVmdF9qb2luKC4sIHN0YXJ3YXJzX25vZGVzX3ZpcywgYnkgPSBjKCJzb3VyY2UiID0gImxhYmVsIikpICU+JSANCiAgDQogICMgTWF0Y2hpbmcgVGFyZ2V0IDwtIFRhcmdldCBOb2RlIGlkICgiaWQueSIpDQogIGxlZnRfam9pbiguLCBzdGFyd2Fyc19ub2Rlc192aXMsIGJ5ID0gYygidGFyZ2V0IiA9ICJsYWJlbCIpKSAlPiUgDQogIA0KIyBTZWxlY3QgImlkLngiIGFuZCAiaWQueSIgT05MWQ0KIyBSZW5hbWUgdGhlbSBhcyAiZnJvbSIgYW5kICJ0byINCiMga2VlcCAid2VpZ2h0IiBjb2x1bW4gZm9yIGFlc3RoZXRpY3Mgb2YgZWRnZXMNCiAgc2VsZWN0KCJmcm9tIiA9IGlkLngsICJ0byIgPSBpZC55LCAidmFsdWUiID0gd2VpZ2h0KQ0KDQojIENoZWNrIGV2ZXJ5dGhpbmcgb25jZQ0Kc3RhcndhcnNfbm9kZXNfdmlzDQpzdGFyd2Fyc19lZGdlc192aXMNCmBgYA0KDQpPaywgbGV0J3MgbWFrZSB0aGluZ3MgbW92ZSBhbmQgc2hha2UhIQ0KDQpgYGB7ciB2aXNOZXR3b3JrLXN0YXJ3YXJzLWZ1dGJvbH0NCnZpc05ldHdvcmsobm9kZXMgPSBzdGFyd2Fyc19ub2Rlc192aXMsDQogICAgICAgICAgIGVkZ2VzID0gc3RhcndhcnNfZWRnZXNfdmlzKSAlPiUgDQogIHZpc05vZGVzKGZvbnQgPSBsaXN0KHNpemUgPSAzMCksIHNoYXBlID0gImljb24iLCANCiAgICAgICAgICAgaWNvbiA9IGxpc3QoY29kZSA9ICJmMWUzIiwgc2l6ZSA9IDc1KSkgJT4lIA0KICBhZGRGb250QXdlc29tZSgpICU+JSANCiAgdmlzRWRnZXMoY29sb3IgPSAicmVkIikNCmBgYA0KDQpgYGB7ciB2aXNOZXR3b3JrLXN0YXJ3YXJzfQ0KdmlzTmV0d29yayhub2RlcyA9IHN0YXJ3YXJzX25vZGVzX3ZpcywNCiAgICAgICAgICAgZWRnZXMgPSBzdGFyd2Fyc19lZGdlc192aXMpICU+JSANCiAgdmlzTm9kZXMoZm9udCA9IGxpc3Qoc2l6ZSA9IDMwKSkgJT4lIA0KICB2aXNFZGdlcyhjb2xvciA9ICJyZWQiKQ0KYGBgDQoNCg0KIyBZb3VyIEFzc2lnbm1lbnRzOg0KDQojIyBNYWtlLTEgOiBXaXRoIGEgcmVhZHkgbWFkZSBkYXRhc2V0DQoNClN0ZXAgMS4gRmlyZSB1cCBhICpuZXcqIFJNYXJrZG93bi4gV3JpdGUgeW91ciBuYW1lLCBmaWxlX25hbWUgYW5kIGRhdGUuDQoNClN0ZXAgMi4gVGFrZSAqKmFueSBvbmUqKiBvZiB0aGUgIk1ha2UxLURhdGFzZXRzIiBkYXRhc2V0cyBkZWNyaWJlZCBiZWxvdy4NCg0KU3RlcCAzLiBSTWFya2Rvd24gY29udGVudHM6ICANCiAgICAtIEludHJvZHVjZSAvIEluc3BlY3QgaW4gUiB5b3VyIGRhdGEgYW5kIGRlc2NyaWJlIA0KICAgIC0gSW50cm9kdWNlIHlvdXIgUHVycG9zZSAtIENyZWF0ZSBncmFwaCBvYmplY3RzLiANCiAgICAtIFdyaXRlIGNvbW1lbnRzIGluIHRoZSBjb2RlIA0KICAgIC0gV3JpdGUgbmFycmF0aXZlIGluIHRleHQgd2l0aCBzZWN0aW9ucywgYm9sZCAsaXRhbGljIGV0Yy4NCg0KU3RlcCA0LiBLbml0IGJlZm9yZSB5b3Ugc3VibWl0LiBTdWJtaXQgb25seSB5b3VyIGtuaXR0YWJsZSBgLlJtZGAgZmlsZS4NCg0KIyMgTWFrZTEgLSBEYXRhc2V0czoNCg0KYSkgIEFpcmxpbmUgRGF0YToNCg0KLSAgIFN0YXJ0IHdpdGggdGhpcyBiaXQgb2YgY29kZSBpbiB5b3VyIHNlY29uZCBjaHVuaywgYWZ0ZXIgYHNldCB1cGANCg0KPmFpcmxpbmVfbm9kZXMgPC0gcmVhZF9jc3YoIi4vRGF0YS9BSVJMSU5FUy1OT0RFUy5jc3YiKSApDQolPiUgbXV0YXRlKElkID0gSWQgKyAxKSANCj5haXJsaW5lX2VkZ2VzIDwtDQpyZWFkX2NzdigiLi9EYXRhL0FJUkxJTkVTLUVER0VTLmNzdiIpICU+JSANCm11dGF0ZShTb3VyY2UgPSBTb3VyY2UgKyAxLCBUYXJnZXQgPSBUYXJnZXQgKyAxKQ0KDQpiKSAgVGhlIEZhbW91cyBaYWNoYXJ5IEthcmF0ZSBDbHViIGRhdGFzZXQNCg0KLSAgIFN0YXJ0IHdpdGggcHVsbGluZyB0aGlzIGRhdGEgaW50byB5b3VyIFJtYXJrZG93bjoNCg0KPmRhdGEoImthcmF0ZSIscGFja2FnZT0gImlncmFwaGRhdGEiKQ0KPmthcmF0ZQ0KDQotICAgVHJ5IGA/a2FyYXRlYCBpbiB0aGUgY29uc29sZQ0KLSAgIE5vdGUgdGhhdCB0aGlzIGlzICoqbm90KiogYSBzZXQgb2Ygbm9kZXMsIG5vciBlZGdlcywgKipidXQqKiBhbHJlYWR5DQogICAgYSAqKmdyYXBoLW9iamVjdCoqIQ0KLSAgIFNvIG5vIG5lZWQgdG8gY3JlYXRlIGEgZ3JhcGggb2JqZWN0IHVzaW5nIGB0YmxfZ3JhcGhgLg0KLSAgIFlvdSB3aWxsIG5lZWQgdG8ganVzdCBnbyBhaGVhZCBhbmQgcGxvdCB1c2luZyBgZ2dyYXBoYC4NCg0KYykgIEdhbWUgb2YgVGhyb25lczoNCg0KLSAgIFN0YXJ0IHdpdGggcHVsbGluZyB0aGlzIGRhdGEgaW50byB5b3VyIFJtYXJrZG93bjoNCg0KPiBHb1QgPC0gcmVhZF9yZHMoIi9EYXRhL0dvVC9Hb1QuUkRTIikNCg0KLSAgIE5vdGUgdGhhdCB0aGlzIGlzIGEgKipsaXN0Kiogb2YgKio3KiogZ3JhcGhzIGZyb20gR2FtZSBvZiBUaHJvbmVzLg0KLSAgIFNlbGVjdCBvbmUgdXNpbmcgYEdvVFtbaW5kZXhdXWAgd2hlcmUgaW5kZXggPSAxLi4uNyBhbmQgdGhlbiBwbG90IGRpcmVjdGx5Lg0KLSBUcnkgdG8gYWNjZXNzIHRoZSBub2RlcyBhbmQgZWRnZXMgYW5kIG1vZGlmeSB0aGVtIHVzaW5nIGFueSBhdHRyaWJ1dGUgZGF0YQ0KDQozLiAgQW55IG90aGVyIGdyYXBoIGRhdGFzZXQgZnJvbSBgaWdyYXBoZGF0YWAgKHR5cGUgYD9pZ3JhcGhkYXRhYCBpbg0KICAgIGNvbnNvbGUpDQoNCi0gICBBc2sgbWUgZm9yIGhlbHAgaWYgeW91IG5lZWQgYW55DQoNCiMjIE1ha2UtMjogTGl0ZXJhcnkgTmV0d29yayB3aXRoIFRWIFNob3cgLyBCb29rIC8gU3RvcnkgLyBQbGF5DQoNClRoaXMgaXMgaW4gZ3JvdXBzLiBHcm91cHMgb2YgNC4NCg0KWW91IG5lZWQgdG8gY3JlYXRlIGEgTmV0d29yayBHcmFwaCBmb3IgeW91ciBmYXZvdXJpdGUgKipCb29rLCBwbGF5LCBUViBzZXJpYWwgb3IgU2hvdyoqLiAoRS5nLiBGcmllbmRzLCBCQlQsIG9yIExCIG9yIEhJTVlNLi4ub3IgSGFtbGV0LCBMaXR0bGUgV29tZW4gLCBQcmlkZSBhbmQgUHJlanVkaWNlLCBvciBMb1RSKQ0KDQpTdGVwIDEuIEdvIHRvOiANCltMaXRlcmFyeSBOZXR3b3Jrc10oaHR0cHM6Ly93d3cudGVhY2hlbmdpbmVlcmluZy5vcmcvYWN0aXZpdGllcy92aWV3L3Vub19ncmFwaHRoZW9yeV9sZXNzb24wMV9hY3Rpdml0eTIpIGZvciBpbnN0cnVjdGlvbnMuIA0KKEluc3RydWN0aW9ucyBhcmUgb24gYWxzbyBUZWFtcyAtPiBGaWxlcy4pDQoNClN0ZXAgMi4gKipNYWtlIHlvdXIgZGF0YSoqIHVzaW5nIHRoZSBpbnN0cnVjdGlvbnMuDQoNCi0gICBJbiB0aGUgbm9kZXMgZXhjZWwsIHVzZSBgaWRgIGFuZCBgbmFtZXNgIGFzIHlvdXIgY29sdW1ucy4gQW55IG90aGVyIGRldGFpbHMgaW4gb3RoZXIgY29sdW1ucyB0byB0aGUgcmlnaHQuDQoNCi0gICBJbiB5b3VyIGBlZGdlc2AgZXhjZWwsIHVzZSBgZnJvbWAgYW5kIGB0b2AgYXJlIHlvdXIgZmlyc3QgY29sdW1ucy4gRW50cmllcyBpbiB0aGVzZSBjb2x1bW5zIGNhbiBiZSBgbmFtZXNgIG9yIGBpZGBzIGJ1dCBiZSBjb25zaXN0ZW50IGFuZCBkb24ndCBtaXguDQoNClN0ZXAgMy4gRGVjaWRlIG9uIDMgYW5zd2VycyB0aGF0IHlvdSB0byBzZWVrIGFuZCBwbGFuIHRvIG1ha2UgZ3JhcGhzIGZvci4NCg0KU3RlcCA0LiBDcmVhdGUgZ3JhcGggb2JqZWN0cy4gU2F5IDMgdmlzdWFsaXphdGlvbnMuDQoNClN0ZXAgNS4gV3JpdGUgY29tbWVudHMvYW5zd2VycyBpbiB0aGUgY29kZSBhbmQgbmFycmF0aXZlIHRleHQuIEFkZCBwaWN0dXJlcyBmcm9tIHRoZSB3ZWIgdXNpbmcgTWFya2Rvd24gc3ludGF4Lg0KDQpTdGVwIDYuIFdyaXRlIFJlZmxlY3Rpb24gKCBvaywgYSBzaG9ydCBvbmUhKSAqaW5zaWRlKiB5b3VyIFJNYXJrZG93bi4gTWFrZSBzdXJlIGl0IGtuaXRzISENCg0KU3RlcCA3LiBHcm91cCBTdWJtaXNzaW9uOiBTdWJtaXQgdGhlIGtuaXR0YWJsZSAqLlJtZCBmaWxlKiAqKkFORCoqIHRoZSBkYXRhLg0KUk1hcmtkb3duIHdpdGggam9pbnQgYXV0aG9yc2hpcC4gRWFjaCBwZXJzb24gc3VibWl0cyBvbiB0aGVpciBBc3NpZ25tZW50cy4gQWxsIGdldCB0aGUgc2FtZSBncmFkZSBvbiB0aGlzIG9uZS4NCg0KQXNrIG1lIGZvciBjbGFyaWZpY2F0aW9ucyBvbiB3aGF0IHRvIGRvICphZnRlciogeW91IGhhdmUgcmVhZCB0aGUgSW5zdHJ1Y3Rpb25zIGluIHlvdXIgZ3JvdXAuDQoNCiMgUmVhZCBtb3JlDQoNCltUaG9tYXMgTGluIFBlZGVyc2VuIC0gMSBnaXJhZmZlLCAyIGdpcmFmZmUsR08hXShodHRwczovL3d3dy5kYXRhLWltYWdpbmlzdC5jb20vMjAxOS8xLWdpcmFmZmUtMi1naXJhZmZlLWdvLykNCg0KSWdyYXBoOiBOZXR3b3JrIEFuYWx5c2lzIGFuZCBWaXN1YWxpemF0aW9uLg0KPGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9aWdyYXBoPi4NCg0KUGVkZXJzZW4sIFRob21hcyBMaW4uIDIwMTdhLiBHZ3JhcGg6IEFuIEltcGxlbWVudGF0aW9uIG9mIEdyYW1tYXIgb2YgR3JhcGhpY3MgZm9yIEdyYXBocyBhbmQgTmV0d29ya3MuDQo8aHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1nZ3JhcGg+Lg0KDQotLS0tLS0tLS0uIDIwMTdiLiBUaWR5Z3JhcGg6IEEgVGlkeSBBcGkgZm9yIEdyYXBoIE1hbmlwdWxhdGlvbi4NCjxodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPXRpZHlncmFwaD4uDQoNClR5bmVyLCBTYW0sIEZyYW7Dp29pcyBCcmlhdHRlLCBhbmQgSGVpa2UgSG9mbWFubi4gMjAxNy4gIk5ldHdvcmsgVmlzdWFsaXphdGlvbiB3aXRoIGdncGxvdDIuIiBUaGUgUiBKb3VybmFsIDkgKDEpOiAyNy0tNTkuDQo8aHR0cHM6Ly9qb3VybmFsLnItcHJvamVjdC5vcmcvYXJjaGl2ZS8yMDE3L1JKLTIwMTctMDIzL2luZGV4Lmh0bWw+Lg0KDQpOZXR3b3JrIERhdGFzZXRzIDxodHRwczovL2ljb24uY29sb3JhZG8uZWR1LyMhL25ldHdvcmtzPg0KDQo=